]> granicus.if.org Git - clang/commitdiff
C++14 init-capture: error out instead of crashing.
authorManman Ren <manman.ren@gmail.com>
Fri, 1 Jul 2016 22:27:16 +0000 (22:27 +0000)
committerManman Ren <manman.ren@gmail.com>
Fri, 1 Jul 2016 22:27:16 +0000 (22:27 +0000)
When we have template arguments, we have a function and a pattern, the variable
in init-capture belongs to the pattern decl when checking if the lhs of
"max = current" is modifiable:
  auto find = [max = init](auto current) {
    max = current;
  };

In function isReferenceToNonConstCapture, we handle the case where the decl
context for the variable is not part of the current context.

Instead of crashing, we emit an error message:
cannot assign to a variable captured by copy in a non-mutable lambda

rdar://26997922

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

lib/Sema/SemaExpr.cpp
test/SemaCXX/cxx1y-init-captures.cpp

index cc2a11fccfb8979ad732533b908b22e03e1f4510..65d234186317718f25be664fd1b367e8c4d00e48 100644 (file)
@@ -9653,7 +9653,16 @@ static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) {
 
   // Decide whether the first capture was for a block or a lambda.
   DeclContext *DC = S.CurContext, *Prev = nullptr;
-  while (DC != var->getDeclContext()) {
+  // Decide whether the first capture was for a block or a lambda.
+  while (DC) {
+    // For init-capture, it is possible that the variable belongs to the
+    // template pattern of the current context.
+    if (auto *FD = dyn_cast<FunctionDecl>(DC))
+      if (var->isInitCapture() &&
+          FD->getTemplateInstantiationPattern() == var->getDeclContext())
+        break;
+    if (DC == var->getDeclContext())
+      break;
     Prev = DC;
     DC = DC->getParent();
   }
index d36882d8e5d14cdd00a142355355bb70afd77b83..d681954707d065b015b9a66909ee036691e8b3c1 100644 (file)
@@ -196,3 +196,13 @@ namespace N3922 {
   auto a = [x{X()}] { return x.n; }; // ok
   auto b = [x = {X()}] {}; // expected-error{{<initializer_list>}}
 }
+
+namespace init_capture_non_mutable {
+void test(double weight) {
+  double init;
+  auto find = [max = init](auto current) {
+    max = current; // expected-error{{cannot assign to a variable captured by copy in a non-mutable lambda}}
+  };
+  find(weight); // expected-note {{in instantiation of function template specialization}}
+}
+}