faisalv updated this revision to Diff 84476.
faisalv added a comment.

The updated patch adds two additional enumerators to 
ExpressionEvaluationContext: ConstantEvaluatedInTemplateArgument and 
ConstantEvaluatedInFunctionSignature and sets them appropriately (as opposed to 
our previous approach of setting the IsLambdaExpressionForbidden flag in those 
locations).

When popping off the EvaluationContext, instead of checking the flag, we now 
check the EvaluationContext directly to determine if the Lambda Expression is 
valid.


Repository:
  rL LLVM

https://reviews.llvm.org/D28510

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Parse/Parser.h
  include/clang/Sema/Sema.h
  lib/Parse/ParseDecl.cpp
  lib/Parse/ParseExpr.cpp
  lib/Parse/ParseTemplate.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaExprMember.cpp
  lib/Sema/SemaLambda.cpp
  lib/Sema/SemaTemplate.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  lib/Sema/TreeTransform.h
  test/SemaCXX/cxx1z-constexpr-lambdas.cpp

Index: test/SemaCXX/cxx1z-constexpr-lambdas.cpp
===================================================================
--- test/SemaCXX/cxx1z-constexpr-lambdas.cpp
+++ test/SemaCXX/cxx1z-constexpr-lambdas.cpp
@@ -157,6 +157,38 @@
 
 } // end ns1_simple_lambda
 
+namespace test_forbidden_lambda_expressions {
+
+template<int N = []{ return 5; }()> struct X { }; //expected-error{{lambda expression may not appear}}
+X<[]{return 10; }()> x; //expected-error{{lambda expression may not appear}}
+void f(int arr[([] { return 5; }())]); //expected-error{{lambda expression may not appear}}
+// FIXME: Should this be ok?
+auto L = [](int arr[([] { return 5; }())]) { }; // OK????
+
+// These should be allowed:
+struct A {
+  int : ([] { return 5; }());
+};
+
+int arr[([] { return 5; }())];
+enum { E = [] { return 5; }() };
+static_assert([]{return 5; }() == 5);
+int *ip = new int[([] { return 5; })()];
+
+int test_case(int x) {
+  switch(x) {
+    case [] { return 5; }(): //OK
+      break;
+    case [] (auto a) { return a; }(6): //expected-note{{previous}}
+      break;
+    case 6:  //expected-error{{duplicate}}
+      break;
+  }
+  return x;
+}
+
+} // end ns forbidden_lambda_expressions
+
 namespace ns1_unimplemented {
 namespace ns1_captures {
 constexpr auto f(int i) {
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -3781,7 +3781,8 @@
   case TemplateArgument::Expression: {
     // Template argument expressions are constant expressions.
     EnterExpressionEvaluationContext Unevaluated(
-        getSema(), Uneval ? Sema::Unevaluated : Sema::ConstantEvaluated);
+        getSema(),
+        Uneval ? Sema::Unevaluated : Sema::ConstantEvaluatedInTemplateArgument);
 
     Expr *InputExpr = Input.getSourceExpression();
     if (!InputExpr) InputExpr = Input.getArgument().getAsExpr();
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2236,8 +2236,8 @@
     Param->setInvalidDecl();
 
   if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
-    EnterExpressionEvaluationContext ConstantEvaluated(SemaRef,
-                                                       Sema::ConstantEvaluated);
+    EnterExpressionEvaluationContext ConstantEvaluated(
+        SemaRef, Sema::ConstantEvaluatedInTemplateArgument);
     ExprResult Value = SemaRef.SubstExpr(D->getDefaultArgument(), TemplateArgs);
     if (!Value.isInvalid())
       Param->setDefaultArgument(Value.get());
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3520,8 +3520,8 @@
   for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
     TemplateArgLists.addOuterTemplateArguments(None);
 
-  EnterExpressionEvaluationContext ConstantEvaluated(SemaRef,
-                                                     Sema::ConstantEvaluated);
+  EnterExpressionEvaluationContext ConstantEvaluated(
+      SemaRef, Sema::ConstantEvaluatedInTemplateArgument);
   return SemaRef.SubstExpr(Param->getDefaultArgument(), TemplateArgLists);
 }
 
@@ -5152,8 +5152,8 @@
 
   // The initialization of the parameter from the argument is
   // a constant-evaluated context.
-  EnterExpressionEvaluationContext ConstantEvaluated(*this,
-                                                     Sema::ConstantEvaluated);
+  EnterExpressionEvaluationContext ConstantEvaluated(
+      *this, Sema::ConstantEvaluatedInTemplateArgument);
 
   if (getLangOpts().CPlusPlus1z) {
     // C++1z [temp.arg.nontype]p1:
Index: lib/Sema/SemaLambda.cpp
===================================================================
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -1591,11 +1591,12 @@
     //   evaluation of e, following the rules of the abstract machine, would
     //   evaluate [...] a lambda-expression.
     //
-    // This is technically incorrect, there are some constant evaluated contexts
-    // where this should be allowed.  We should probably fix this when DR1607 is
-    // ratified, it lays out the exact set of conditions where we shouldn't
-    // allow a lambda-expression.
+    // In C++1z, lambda-expressions are allowed in certain contexts - which
+    // is handled when the expression evaluation context is popped off.
     case ConstantEvaluated:
+    case ConstantEvaluatedInFunctionSignature:
+    case ConstantEvaluatedInTemplateArgument:
+
       // We don't actually diagnose this case immediately, because we
       // could be within a context where we might find out later that
       // the expression is potentially evaluated (e.g., for typeid).
Index: lib/Sema/SemaExprMember.cpp
===================================================================
--- lib/Sema/SemaExprMember.cpp
+++ lib/Sema/SemaExprMember.cpp
@@ -145,6 +145,8 @@
 
   case Sema::DiscardedStatement:
   case Sema::ConstantEvaluated:
+  case Sema::ConstantEvaluatedInFunctionSignature:
+  case Sema::ConstantEvaluatedInTemplateArgument:
   case Sema::PotentiallyEvaluated:
   case Sema::PotentiallyEvaluatedIfUsed:
     break;
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -13104,19 +13104,30 @@
   unsigned NumTypos = Rec.NumTypos;
 
   if (!Rec.Lambdas.empty()) {
-    if (Rec.isUnevaluated() || Rec.Context == ConstantEvaluated) {
-      unsigned D;
+    if (Rec.isUnevaluated() || Rec.isConstantEvaluated()) {
+      unsigned D = 0;
       if (Rec.isUnevaluated()) {
         // C++11 [expr.prim.lambda]p2:
         //   A lambda-expression shall not appear in an unevaluated operand
         //   (Clause 5).
         D = diag::err_lambda_unevaluated_operand;
-      } else {
-        // C++1y [expr.const]p2:
-        //   A conditional-expression e is a core constant expression unless the
-        //   evaluation of e, following the rules of the abstract machine, would
-        //   evaluate [...] a lambda-expression.
-        D = diag::err_lambda_in_constant_expression;
+      } else {   
+        // C++1z allows lambda expressions in constant expressions that are not
+        // within template arguments or function signatures.
+        if (getLangOpts().CPlusPlus1z) {
+          if (Rec.Context == Sema::ConstantEvaluatedInFunctionSignature) 
+            D = diag::err_lambda_in_function_signature;
+          else if (Rec.Context == Sema::ConstantEvaluatedInTemplateArgument)
+            D = diag::err_lambda_in_template_argument;
+        } else {
+          // C++14 [expr.const]p2:
+          //   A conditional-expression e is a core constant expression unless
+          //   the
+          //   evaluation of e, following the rules of the abstract machine,
+          //   would
+          //   evaluate [...] a lambda-expression.
+          D = diag::err_lambda_in_constant_expression;
+        }
       }
 
       // C++1z allows lambda expressions as core constant expressions.
@@ -13125,9 +13136,10 @@
       // are part of function-signatures.  Be mindful that P0315 (Lambdas in
       // unevaluated contexts) might lift some of these restrictions in a 
       // future version.
-      if (Rec.Context != ConstantEvaluated || !getLangOpts().CPlusPlus1z)
+      if (D) {
         for (const auto *L : Rec.Lambdas)
           Diag(L->getLocStart(), D);
+      }
     } else {
       // Mark the capture expressions odr-used. This was deferred
       // during lambda expression creation.
@@ -13142,7 +13154,7 @@
   // temporaries that we may have created as part of the evaluation of
   // the expression in that context: they aren't relevant because they
   // will never be constructed.
-  if (Rec.isUnevaluated() || Rec.Context == ConstantEvaluated) {
+  if (Rec.isUnevaluated() || Rec.isConstantEvaluated()) {
     ExprCleanupObjects.erase(ExprCleanupObjects.begin() + Rec.NumCleanupObjects,
                              ExprCleanupObjects.end());
     Cleanup = Rec.ParentCleanup;
@@ -13192,6 +13204,8 @@
 
     case Sema::UnevaluatedList:
     case Sema::ConstantEvaluated:
+    case Sema::ConstantEvaluatedInTemplateArgument:
+    case Sema::ConstantEvaluatedInFunctionSignature:
     case Sema::PotentiallyEvaluated:
       // Expressions in this context could be evaluated.
       return true;
@@ -13221,6 +13235,8 @@
       return false;
 
     case Sema::ConstantEvaluated:
+    case Sema::ConstantEvaluatedInTemplateArgument:
+    case Sema::ConstantEvaluatedInFunctionSignature:
     case Sema::PotentiallyEvaluated:
       return true;
 
@@ -14511,6 +14527,9 @@
     break;
 
   case ConstantEvaluated:
+  case ConstantEvaluatedInTemplateArgument:
+  case ConstantEvaluatedInFunctionSignature:
+
     // Relevant diagnostics should be produced by constant evaluation.
     break;
 
Index: lib/Parse/ParseTemplate.cpp
===================================================================
--- lib/Parse/ParseTemplate.cpp
+++ lib/Parse/ParseTemplate.cpp
@@ -701,8 +701,8 @@
     //   end of the template-parameter-list rather than a greater-than
     //   operator.
     GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
-    EnterExpressionEvaluationContext ConstantEvaluated(Actions,
-                                                       Sema::ConstantEvaluated);
+    EnterExpressionEvaluationContext ConstantEvaluated(
+        Actions, Sema::ConstantEvaluatedInTemplateArgument);
 
     DefaultArg = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
     if (DefaultArg.isInvalid())
@@ -1220,7 +1220,8 @@
   
   // Parse a non-type template argument. 
   SourceLocation Loc = Tok.getLocation();
-  ExprResult ExprArg = ParseConstantExpression(MaybeTypeCast);
+  ExprResult ExprArg = ParseConstantExpression(
+      MaybeTypeCast, ConstantEvaluationContext::InTemplateArgument);
   if (ExprArg.isInvalid() || !ExprArg.get())
     return ParsedTemplateArgument();
 
Index: lib/Parse/ParseExpr.cpp
===================================================================
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -192,15 +192,29 @@
   return ParseRHSOfBinaryExpression(R, prec::Assignment);
 }
 
-
-ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) {
+ExprResult Parser::ParseConstantExpression(
+    TypeCastState isTypeCast,
+    ConstantEvaluationContext ConstantEvalContext) {
+  
+  const Sema::ExpressionEvaluationContext EvalCtx =
+    [ConstantEvalContext] {
+    switch (ConstantEvalContext) {
+    case ConstantEvaluationContext::Default:
+      return Sema::ConstantEvaluated;
+    case ConstantEvaluationContext::InFunctionSignature:
+      return Sema::ConstantEvaluatedInFunctionSignature;
+    case ConstantEvaluationContext::InTemplateArgument:
+      return Sema::ConstantEvaluatedInTemplateArgument;
+    }
+    llvm_unreachable("all cases should be handled above");
+  }();
+  
   // 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::ConstantEvaluated);
-
+  EnterExpressionEvaluationContext ConstantEvaluated(
+      Actions, EvalCtx);
   ExprResult LHS(ParseCastExpression(false, false, isTypeCast));
   ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
   return Actions.ActOnConstantExpression(Res);
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp
+++ lib/Parse/ParseDecl.cpp
@@ -6247,7 +6247,11 @@
     // Parse the constant-expression or assignment-expression now (depending
     // on dialect).
     if (getLangOpts().CPlusPlus) {
-      NumElements = ParseConstantExpression();
+      NumElements = ParseConstantExpression(
+          NotTypeCast,
+          D.getContext() == D.PrototypeContext
+              ? Parser::ConstantEvaluationContext::InFunctionSignature
+              : Parser::ConstantEvaluationContext::Default);
     } else {
       EnterExpressionEvaluationContext Unevaluated(Actions,
                                                    Sema::ConstantEvaluated);
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -829,6 +829,18 @@
     /// cases in a switch statement).
     ConstantEvaluated,
 
+    /// \brief Like ConstantEvaluated above, except that the compile-time
+    /// evaluation is occuring within a template argument context. This
+    /// distinction is useful because certain expressions (lambda expressions,
+    /// even immediately invoked ones) are forbidden in such contexts.
+    ConstantEvaluatedInTemplateArgument,
+
+    /// \brief Like ConstantEvaluated above, except that the compile-time
+    /// evaluation is occuring within a function signature. This
+    /// distinction is useful because certain expressions (lambda expressions,
+    /// even immediately invoked ones) are forbidden in such contexts.
+    ConstantEvaluatedInFunctionSignature,
+
     /// \brief The current expression is potentially evaluated at run time,
     /// which means that code may be generated to evaluate the value of the
     /// expression at run time.
@@ -909,6 +921,17 @@
       return Context == Unevaluated || Context == UnevaluatedAbstract ||
              Context == UnevaluatedList;
     }
+    bool isConstantEvaluated() const {
+      switch (Context) {
+        case ConstantEvaluated:
+        case ConstantEvaluatedInTemplateArgument:
+        case ConstantEvaluatedInFunctionSignature:
+          return true;
+        default:
+          return false;
+      }
+      llvm_unreachable("all control flow handled within switch");
+    }
   };
 
   /// A stack of expression evaluation contexts.
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -1423,9 +1423,15 @@
     MaybeTypeCast,
     IsTypeCast
   };
-
+  enum class ConstantEvaluationContext {
+    Default,
+    InTemplateArgument,
+    InFunctionSignature
+  };
   ExprResult ParseExpression(TypeCastState isTypeCast = NotTypeCast);
-  ExprResult ParseConstantExpression(TypeCastState isTypeCast = NotTypeCast);
+  ExprResult ParseConstantExpression(
+      TypeCastState isTypeCast = NotTypeCast,
+      ConstantEvaluationContext Ctx = ConstantEvaluationContext::Default);
   ExprResult ParseConstraintExpression();
   // Expr that doesn't include commas.
   ExprResult ParseAssignmentExpression(TypeCastState isTypeCast = NotTypeCast);
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -6278,6 +6278,10 @@
     "lambda expression in an unevaluated operand">;
   def err_lambda_in_constant_expression : Error<
     "a lambda expression may not appear inside of a constant expression">;
+  def err_lambda_in_template_argument : Error<
+    "a lambda expression may not appear inside of a template argument">;
+  def err_lambda_in_function_signature : Error<
+    "a lambda expression may not appear inside of a function signature">;
   def err_lambda_return_init_list : Error<
     "cannot deduce lambda return type from initializer list">;
   def err_lambda_capture_default_arg : Error<
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to