faisalv updated this revision to Diff 96858.
faisalv marked 3 inline comments as done.
faisalv added a comment.

Updated the patch following Richard's feedback:

- teach ParseConstantExpression to create its own ExpressionEvaluationContext 
only if asked to.


https://reviews.llvm.org/D31588

Files:
  include/clang/Parse/Parser.h
  lib/Parse/ParseExpr.cpp
  lib/Parse/ParseTemplate.cpp
  test/SemaCXX/lambda-expressions.cpp
  test/SemaCXX/local-classes.cpp

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<int> struct X {};
+  
+  void foo() {
+    const int N = 10;
+  
+    struct Local {
+      void f(X<N>) {} // OK
+    }; 
+  }
+}
Index: test/SemaCXX/lambda-expressions.cpp
===================================================================
--- test/SemaCXX/lambda-expressions.cpp
+++ test/SemaCXX/lambda-expressions.cpp
@@ -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<int> struct X {};
+  
+  void foo() {
+    const int N = 10;
+    (void) [] { X<N> x; };
+  }
+}
Index: lib/Parse/ParseTemplate.cpp
===================================================================
--- lib/Parse/ParseTemplate.cpp
+++ lib/Parse/ParseTemplate.cpp
@@ -1198,42 +1198,48 @@
   //   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,
+      true /*Don't create another ConstantExpressionEvaluationContext*/);
   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 +1280,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: 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<alignof(EnterExpressionEvaluationContext),
+                           sizeof(EnterExpressionEvaluationContext)>
+        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: 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);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to