This is an archive of the discontinued LLVM Phabricator instance.

Allow dllimport non-type template arguments in C++17
ClosedPublic

Authored by rnk on Feb 14 2018, 2:54 PM.

Diff Detail

Repository
rC Clang

Event Timeline

rnk created this revision.Feb 14 2018, 2:54 PM
rsmith added inline comments.Feb 14 2018, 4:38 PM
clang/lib/AST/ExprConstant.cpp
10166–10182 ↗(On Diff #134324)

Neither EM_ConstantFold nor EM_IgnoreSideEffects seem like the right evaluation modes to be using to evaluate a non-type template argument. I would expect EM_ConstantExpression to be used for both cases.

rsmith added inline comments.Feb 14 2018, 4:42 PM
clang/lib/AST/ExprConstant.cpp
10166–10182 ↗(On Diff #134324)

Oh, I see, we're allowing side-effects here and then issuing a constant-folding warning elsewhere if there actually were any. *sigh*

I would expect we can get away with not doing that for template arguments. It'd be worth testing whether GCC actually allows constant folding there, or requires a real constant expression.

clang/lib/Sema/SemaOverload.cpp
5401 ↗(On Diff #134324)

Don't we get here for CCEKinds other than the non-type template argument case?

rnk added inline comments.Feb 15 2018, 10:59 AM
clang/lib/AST/ExprConstant.cpp
10166–10182 ↗(On Diff #134324)

"Allowing side effects" here looks like it really means allowing non-constant subexpressions when those subexpressions would be discarded:

template <int *N> struct Foo {};
int x;
Foo<(x, &x)> f;

constexpr bool is_true = true;

int *fn() {
  if constexpr (((void)x, &x) != nullptr) {
    return &x;
  } else {
    return nullptr;
  }

  if constexpr (is_true || x == 2) {
    return &x;
  } else {
    return nullptr;
  }
}

Clang accepts this, GCC rejects a few. I'm guessing we want that kind of behavior for if constexpr conditions, but maybe not for non-type template parameters.

So, it sounds like we should check the CCE kind in SemaOverload, and use a more restrictive constant expression evaluation mode in that case. Perhaps even a new one for non-type template arguments.

clang/lib/Sema/SemaOverload.cpp
5401 ↗(On Diff #134324)

You're right, but I wasn't able to construct a test case where we would call CheckConvertedConstantExpression and we would reject it today because it is dllimported. This was my best idea, using if constexpr:

struct __declspec(dllimport) Foo {
  static constexpr bool imported_foo = true;
};
const bool some_bool = false;
const bool *f() {
  if constexpr (Foo::imported_foo) {
    return &Foo::imported_foo;
  } else {
    return &some_bool;
  }
}

Any other ideas on how to get more coverage of this path through CheckConvertedConstantExpression?

rnk updated this revision to Diff 134510.Feb 15 2018, 2:25 PM
  • revise as discussed
rsmith added inline comments.Feb 15 2018, 6:45 PM
clang/include/clang/AST/Expr.h
103 ↗(On Diff #134510)

If we end up moving this out of Sema into the clang namespace, it needs a longer name than this.

670–672 ↗(On Diff #134510)

Seems strange to pass a converted constant expression kind to an 'evaluate as core constant expression' function. And it seems like we don't need the kind here, just an "evaluating for emission w/relocations" vs "evaluating for mangling" enum.

Also, we need to evaluate non-type template arguments as constant expressions, not just as core constant expressions, which the implementation does, but the name and comment here don't reflect. (The difference is that you can't result in a pointer/reference to a temporary or automatic / thread storage duration entity.)

rnk edited the summary of this revision. (Show Details)May 9 2018, 4:05 PM
rnk updated this revision to Diff 146025.May 9 2018, 4:06 PM
  • don't expose CCEK, use a bool
rnk added inline comments.May 9 2018, 4:09 PM
clang/include/clang/AST/Expr.h
670–672 ↗(On Diff #134510)

So... what are these things? Converted constant expressions? What are we evaluating them as? I guess they're not rvalues or lvalues.

rsmith added inline comments.May 9 2018, 4:34 PM
clang/include/clang/AST/Expr.h
663 ↗(On Diff #146025)

I would prefer an enum { EvaluateForCodeGen, EvaluateForMangling } over a bool IsTemplateArg; I would not be surprised if we find other cases where we want to evaluate an expression for mangling purposes only.

670–672 ↗(On Diff #134510)

I think this should just be called EvaluateAsConstantExpr, and you should drop all the "core"s throughout. The difference between a constant expression and a core constant expression is that a core constant expression allows the evaluated value to refer to entities with automatic storage duration etc, which is exactly the case you want to disallow here :)

I also don't think you need the ParamType, and can instead just look at whether the expression itself is an rvalue.

clang/lib/AST/ExprConstant.cpp
707 ↗(On Diff #146025)

No "core" here.

709 ↗(On Diff #146025)

I don't think we need this. See below.

10384–10385 ↗(On Diff #146025)

Instead of a new EvaluationMode which is actually not used by evaluation, we could pass a parameter into CheckLValueConstantExpression to indicate if we're in the "for-mangling" mode.

10397 ↗(On Diff #146025)

If you switch from using ParamType->isReferenceType() to asking the expression for its value category, you don't need the implicit-lvalue-to-rvalue-conversion semantics of EvaluateAsRValue, and can just call ::Evaluate here followed by a call to CheckConstantExpression (passing the latter the IsTemplateArg flag).

In fact, you don't need the separate case for lvalues above, either, since ::Evaluate does the right thing for an lvalue expression by itself.

clang/lib/Sema/SemaOverload.cpp
5401 ↗(On Diff #134324)

All the other forms of CCEKind also set RequireInt to true, and so any case your check catches would also be caught on the line below.

rnk updated this revision to Diff 146039.May 9 2018, 5:29 PM
  • getting closer
rnk added inline comments.May 9 2018, 5:30 PM
clang/include/clang/AST/Expr.h
662 ↗(On Diff #146039)

I expect we could come up with a better name, but is this closer to what you had in mind?

rsmith accepted this revision.May 9 2018, 6:08 PM
rsmith added inline comments.
clang/lib/AST/ExprConstant.cpp
1871–1902 ↗(On Diff #146039)

Usage should be passed into these recursive calls to CheckConstantExpression, although that's NFC for now, until/unless we start allowing class types as template parameters.

This revision is now accepted and ready to land.May 9 2018, 6:08 PM
This revision was automatically updated to reflect the committed changes.
rnk added a comment.May 10 2018, 1:27 PM

Thanks for the guidance!

clang/lib/AST/ExprConstant.cpp
1871–1902 ↗(On Diff #146039)

Makes sense, done.