diff options
-rw-r--r-- | clang/include/clang/Parse/Parser.h | 1 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 15 | ||||
-rw-r--r-- | clang/lib/Parse/ParseTemplate.cpp | 14 | ||||
-rw-r--r-- | clang/test/SemaCXX/lambda-expressions.cpp | 14 | ||||
-rw-r--r-- | clang/test/SemaCXX/local-classes.cpp | 12 |
5 files changed, 45 insertions, 11 deletions
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index c97b4059250..537796fa646 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1460,6 +1460,7 @@ public: }; ExprResult ParseExpression(TypeCastState isTypeCast = NotTypeCast); + ExprResult ParseConstantExpressionInExprEvalContext(TypeCastState isTypeCast); ExprResult ParseConstantExpression(TypeCastState isTypeCast = NotTypeCast); ExprResult ParseConstraintExpression(); // Expr that doesn't include commas. diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index bcdc72df305..c739a50f0b3 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -192,6 +192,16 @@ Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc, return ParseRHSOfBinaryExpression(R, prec::Assignment); } +ExprResult +Parser::ParseConstantExpressionInExprEvalContext(TypeCastState isTypeCast) { + assert(Actions.ExprEvalContexts.back().Context == + Sema::ExpressionEvaluationContext::ConstantEvaluated && + "Call this function only if your ExpressionEvaluationContext is " + "already ConstantEvaluated"); + ExprResult LHS(ParseCastExpression(false, false, isTypeCast)); + ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + return Actions.ActOnConstantExpression(Res); +} ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) { // C++03 [basic.def.odr]p2: @@ -200,10 +210,7 @@ ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) { // C++98 and C++11 have no such rule, but this is only a defect in C++98. EnterExpressionEvaluationContext ConstantEvaluated( Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); - - ExprResult LHS(ParseCastExpression(false, false, isTypeCast)); - ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); - return Actions.ActOnConstantExpression(Res); + return ParseConstantExpressionInExprEvalContext(isTypeCast); } /// \brief Parse a constraint-expression. diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 28ae113a511..a919d870810 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -1186,7 +1186,13 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { // expression is resolved to a type-id, regardless of the form of // the corresponding template-parameter. // - // Therefore, we initially try to parse a type-id. + // Therefore, we initially try to parse a type-id - and isCXXTypeId might look + // up and annotate an identifier as an id-expression during disambiguation, + // so enter the appropriate context for a constant expression template + // argument before trying to disambiguate. + + EnterExpressionEvaluationContext EnterConstantEvaluated( + Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); if (isCXXTypeId(TypeIdAsTemplateArgument)) { SourceLocation Loc = Tok.getLocation(); TypeResult TypeArg = ParseTypeName(/*Range=*/nullptr, @@ -1216,7 +1222,7 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { // Parse a non-type template argument. SourceLocation Loc = Tok.getLocation(); - ExprResult ExprArg = ParseConstantExpression(MaybeTypeCast); + ExprResult ExprArg = ParseConstantExpressionInExprEvalContext(MaybeTypeCast); if (ExprArg.isInvalid() || !ExprArg.get()) return ParsedTemplateArgument(); @@ -1262,9 +1268,7 @@ bool Parser::IsTemplateArgumentList(unsigned Skip) { /// template-argument-list ',' template-argument bool Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { - // Template argument lists are constant-evaluation contexts. - EnterExpressionEvaluationContext EvalContext( - Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); + ColonProtectionRAIIObject ColonProtection(*this, false); do { diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp index e0ab15dc632..efbb47681ad 100644 --- a/clang/test/SemaCXX/lambda-expressions.cpp +++ b/clang/test/SemaCXX/lambda-expressions.cpp @@ -525,9 +525,9 @@ template <int N> class S {}; void foo() { - const int num = 18; // expected-note {{'num' declared here}} + const int num = 18; auto outer = []() { - auto inner = [](S<num> &X) {}; // expected-error {{variable 'num' cannot be implicitly captured in a lambda with no capture-default specified}} + auto inner = [](S<num> &X) {}; }; } } @@ -573,3 +573,13 @@ void foo1() { auto s1 = S1{[name=name]() {}}; // expected-error {{use of undeclared identifier 'name'; did you mean 'name1'?}} } } + +namespace PR25627_dont_odr_use_local_consts { + + template<int> struct X {}; + + void foo() { + const int N = 10; + (void) [] { X<N> x; }; + } +} diff --git a/clang/test/SemaCXX/local-classes.cpp b/clang/test/SemaCXX/local-classes.cpp index f4ca79159dc..eb0b7e43ebe 100644 --- a/clang/test/SemaCXX/local-classes.cpp +++ b/clang/test/SemaCXX/local-classes.cpp @@ -40,3 +40,15 @@ namespace Templates { }; } } + +namespace PR25627_dont_odr_use_local_consts { + template<int> struct X { X(); X(int); }; + + void foo() { + const int N = 10; + + struct Local { + void f(X<N> = X<N>()) {} // OK + }; + } +} |