Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -1449,7 +1449,9 @@ }; ExprResult ParseExpression(TypeCastState isTypeCast = NotTypeCast); - ExprResult ParseConstantExpression(TypeCastState isTypeCast = NotTypeCast); + ExprResult + ParseConstantExpression(TypeCastState isTypeCast = NotTypeCast, + bool CreateOwnExpressionEvaluationContext = true); ExprResult ParseConstraintExpression(); // Expr that doesn't include commas. ExprResult ParseAssignmentExpression(TypeCastState isTypeCast = NotTypeCast); Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -192,17 +192,38 @@ return ParseRHSOfBinaryExpression(R, prec::Assignment); } - -ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) { +ExprResult +Parser::ParseConstantExpression(TypeCastState isTypeCast, + bool CreateOwnExpressionEvaluationContext) { // C++03 [basic.def.odr]p2: // An expression is potentially evaluated unless it appears where an // integral constant expression is required (see 5.19) [...]. // C++98 and C++11 have no such rule, but this is only a defect in C++98. - EnterExpressionEvaluationContext ConstantEvaluated( - Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); + // Create the ExpressionEvaluationContext on the stack - but only if asked to. + struct EnterExpressionEvaluationContextConditionalRAII { + llvm::AlignedCharArray + MyStackStorage; + const EnterExpressionEvaluationContext *const ConstantEvaluatedContext; + EnterExpressionEvaluationContextConditionalRAII(bool CreateIt, + Sema &Actions) + : ConstantEvaluatedContext( + CreateIt + ? new (&MyStackStorage) EnterExpressionEvaluationContext( + Actions, + Sema::ExpressionEvaluationContext::ConstantEvaluated) + : nullptr) {} + ~EnterExpressionEvaluationContextConditionalRAII() { + if (ConstantEvaluatedContext) + ConstantEvaluatedContext->~EnterExpressionEvaluationContext(); + } + } EnterExpressionEvaluationContextConditionalRAII( + CreateOwnExpressionEvaluationContext, Actions); + ExprResult LHS(ParseCastExpression(false, false, isTypeCast)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + return Actions.ActOnConstantExpression(Res); } Index: lib/Parse/ParseTemplate.cpp =================================================================== --- lib/Parse/ParseTemplate.cpp +++ lib/Parse/ParseTemplate.cpp @@ -1198,42 +1198,49 @@ // 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, - Declarator::TemplateTypeArgContext); + TypeResult TypeArg = + ParseTypeName(/*Range=*/nullptr, Declarator::TemplateTypeArgContext); if (TypeArg.isInvalid()) return ParsedTemplateArgument(); - + return ParsedTemplateArgument(ParsedTemplateArgument::Type, - TypeArg.get().getAsOpaquePtr(), - Loc); + TypeArg.get().getAsOpaquePtr(), Loc); } - // Try to parse a template template argument. { TentativeParsingAction TPA(*this); - ParsedTemplateArgument TemplateTemplateArgument - = ParseTemplateTemplateArgument(); + ParsedTemplateArgument TemplateTemplateArgument = + ParseTemplateTemplateArgument(); if (!TemplateTemplateArgument.isInvalid()) { TPA.Commit(); return TemplateTemplateArgument; } - + // Revert this tentative parse to parse a non-type template argument. TPA.Revert(); } - - // Parse a non-type template argument. + + // Parse a non-type template argument. SourceLocation Loc = Tok.getLocation(); - ExprResult ExprArg = ParseConstantExpression(MaybeTypeCast); + ExprResult ExprArg = ParseConstantExpression( + MaybeTypeCast, + false /*don't create another ConstantExpressionEvaluationContext, + use ours instead*/); if (ExprArg.isInvalid() || !ExprArg.get()) return ParsedTemplateArgument(); - return ParsedTemplateArgument(ParsedTemplateArgument::NonType, - ExprArg.get(), Loc); + return ParsedTemplateArgument(ParsedTemplateArgument::NonType, ExprArg.get(), + Loc); } /// \brief Determine whether the current tokens can only be parsed as a @@ -1274,16 +1281,16 @@ /// 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 { ParsedTemplateArgument Arg = ParseTemplateArgument(); SourceLocation EllipsisLoc; - if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) + if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) { + // FIXME: Do we need need to enter a constant evaluation context here? Arg = Actions.ActOnPackExpansion(Arg, EllipsisLoc); + } if (Arg.isInvalid()) { SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch); Index: test/SemaCXX/lambda-expressions.cpp =================================================================== --- test/SemaCXX/lambda-expressions.cpp +++ test/SemaCXX/lambda-expressions.cpp @@ -525,9 +525,9 @@ class S {}; void foo() { - const int num = 18; // expected-note {{'num' declared here}} + const int num = 18; auto outer = []() { - auto inner = [](S &X) {}; // expected-error {{variable 'num' cannot be implicitly captured in a lambda with no capture-default specified}} + auto inner = [](S &X) {}; }; } } @@ -573,3 +573,13 @@ auto s1 = S1{[name=name]() {}}; // expected-error {{use of undeclared identifier 'name'; did you mean 'name1'?}} } } + +namespace PR25627_dont_odr_use_local_consts { + + template struct X {}; + + void foo() { + const int N = 10; + (void) [] { X x; }; + } +} Index: test/SemaCXX/local-classes.cpp =================================================================== --- test/SemaCXX/local-classes.cpp +++ test/SemaCXX/local-classes.cpp @@ -40,3 +40,15 @@ }; } } + +namespace PR25627_dont_odr_use_local_consts { + template struct X {}; + + void foo() { + const int N = 10; + + struct Local { + void f(X) {} // OK + }; + } +}