]> granicus.if.org Git - clang/commitdiff
Link together the call operator produced from transforming a lambda
authorDouglas Gregor <dgregor@apple.com>
Tue, 14 Feb 2012 00:00:48 +0000 (00:00 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 14 Feb 2012 00:00:48 +0000 (00:00 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150440 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaLambda.cpp
lib/Sema/TreeTransform.h
test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp

index f97b5232acfd7f90f5b9dbd081ba0ff7382f3a3f..0ce1c741638ad1925b5e94cc64de670a2d5c4396 100644 (file)
@@ -521,19 +521,21 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
   // 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;
-
-  case ConstantEvaluated:
-  case PotentiallyEvaluated:
-  case PotentiallyEvaluatedIfUsed:
-    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;
+    }
+  }
+  
   return MaybeBindToTemporary(Lambda);
 }
index ba6ec82c8101d92cb3566d51e87401865cb53c6d..a63b9c804ac0acc74a4ff78408891c583e2be441 100644 (file)
@@ -7672,6 +7672,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
                                       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 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
   }
 
   // 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, 
index 4126dd96b97df72612ca27f63a16823de9734293..baa29ea944301579098f94979a2f2b911fc79460 100644 (file)
@@ -43,3 +43,74 @@ int infer_result(T x, T y) {
 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&);
+}