[cfe-commits] r150440 - in /cfe/trunk: lib/Sema/SemaLambda.cpp lib/Sema/TreeTransform.h test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp

Douglas Gregor dgregor at apple.com
Mon Feb 13 16:00:48 PST 2012


Author: dgregor
Date: Mon Feb 13 18:00:48 2012
New Revision: 150440

URL: http://llvm.org/viewvc/llvm-project?rev=150440&view=rev
Log:
Link together the call operator produced from transforming a lambda
expression with the original call operator, so that we don't try to
separately instantiate the call operator. Test and tweak a few more
bits for template instantiation of lambda expressions.

Modified:
    cfe/trunk/lib/Sema/SemaLambda.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp

Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=150440&r1=150439&r2=150440&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Mon Feb 13 18:00:48 2012
@@ -521,19 +521,21 @@
   // C++11 [expr.prim.lambda]p2:
   //   A lambda-expression shall not appear in an unevaluated operand
   //   (Clause 5).
-  switch (ExprEvalContexts.back().Context) {
-  case Unevaluated:
-    // 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).
-    ExprEvalContexts.back().Lambdas.push_back(Lambda);
-    break;
+  if (!CurContext->isDependentContext()) {
+    switch (ExprEvalContexts.back().Context) {
+    case Unevaluated:
+      // 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).
+      ExprEvalContexts.back().Lambdas.push_back(Lambda);
+      break;
 
-  case ConstantEvaluated:
-  case PotentiallyEvaluated:
-  case PotentiallyEvaluatedIfUsed:
-    break;
+    case ConstantEvaluated:
+    case PotentiallyEvaluated:
+    case PotentiallyEvaluatedIfUsed:
+      break;
+    }
   }
-
+  
   return MaybeBindToTemporary(Lambda);
 }

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=150440&r1=150439&r2=150440&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Mon Feb 13 18:00:48 2012
@@ -7672,6 +7672,13 @@
                                       E->getCallOperator()->getLocEnd());
   getDerived().transformAttrs(E->getCallOperator(), CallOperator);
   
+  // FIXME: Instantiation-specific.
+  CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(), 
+                                                 TSK_ImplicitInstantiation);
+
+  // Introduce the context of the call operator.
+  Sema::ContextRAII SavedContext(getSema(), CallOperator);
+
   // Enter the scope of the lambda.
   sema::LambdaScopeInfo *LSI
     = getSema().enterLambdaScope(CallOperator, E->getIntroducerRange(),
@@ -7741,17 +7748,12 @@
   }
 
   // Instantiate the body of the lambda expression.
-  StmtResult Body;
-  {
-    Sema::ContextRAII SavedContext(getSema(), CallOperator);
-    
-    Body = getDerived().TransformStmt(E->getBody());
-    if (Body.isInvalid()) {
-      getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/0, 
-                                 /*IsInstantiation=*/true);
-      return ExprError();    
-    }
-  } 
+  StmtResult Body = getDerived().TransformStmt(E->getBody());
+  if (Body.isInvalid()) {
+    getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/0, 
+                               /*IsInstantiation=*/true);
+    return ExprError();    
+  }
   
   return getSema().ActOnLambdaExpr(E->getLocStart(), Body.take(), 
                                    /*CurScope=*/0, 

Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp?rev=150440&r1=150439&r2=150440&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp Mon Feb 13 18:00:48 2012
@@ -43,3 +43,74 @@
 template int infer_result(int, int);
 template int infer_result(X, X); // expected-note{{in instantiation of function template specialization 'infer_result<X>' requested here}}
 
+// Make sure that lambda's operator() can be used from templates.
+template<typename F>
+void accept_lambda(F f) {
+  f(1);
+}
+
+template<typename T>
+void pass_lambda(T x) {
+  accept_lambda([&x](T y) { return x + y; });
+}
+
+template void pass_lambda(int);
+
+namespace std {
+  class type_info;
+}
+
+namespace p2 {
+  struct P {
+    virtual ~P();
+  };
+
+  template<typename T>
+  struct Boom {
+    Boom(const Boom&) { 
+      T* x = 1; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} \
+      // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}}
+    }
+    void tickle() const;
+  };
+  
+  template<typename R, typename T>
+  void odr_used(R &r, Boom<T> boom) {
+    const std::type_info &ti
+      = typeid([=,&r] () -> R& { // expected-error{{lambda expression in an unevaluated operand}}
+          boom.tickle(); // expected-note{{in instantiation of member function}}
+          return r; 
+        }()); 
+  }
+
+  template void odr_used(int&, Boom<int>); // expected-note{{in instantiation of function template specialization}}
+
+  template<typename R, typename T>
+  void odr_used2(R &r, Boom<T> boom) {
+    const std::type_info &ti
+      = typeid([=,&r] () -> R& {
+          boom.tickle(); // expected-note{{in instantiation of member function}}
+          return r; 
+        }()); 
+  }
+
+  template void odr_used2(P&, Boom<float>);
+}
+
+namespace p5 {
+  struct NonConstCopy {
+    NonConstCopy(const NonConstCopy&) = delete;
+    NonConstCopy(NonConstCopy&);
+  };
+
+  template<typename T>
+  void double_capture(T &nc) {
+    [=] () mutable {
+      [=] () mutable {
+        T nc2(nc);
+      }();
+    }();
+  }
+
+  template void double_capture(NonConstCopy&);
+}





More information about the cfe-commits mailing list