[cfe-commits] r149937 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaExpr.cpp test/CXX/class/class.local/p1-0x.cpp test/CXX/class/class.local/p1.cpp test/CXX/class/class.local/p3.cpp test/SemaCXX/c99-variable-length-array.cpp

Eli Friedman eli.friedman at gmail.com
Mon Feb 6 16:15:00 PST 2012


Author: efriedma
Date: Mon Feb  6 18:15:00 2012
New Revision: 149937

URL: http://llvm.org/viewvc/llvm-project?rev=149937&view=rev
Log:
Misc improvements to the diagnostic when a variable is odr-used in a context that is not allowed to capture variables.

Fixes PR11883.


Added:
    cfe/trunk/test/CXX/class/class.local/p1-0x.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/test/CXX/class/class.local/p1.cpp
    cfe/trunk/test/CXX/class/class.local/p3.cpp
    cfe/trunk/test/SemaCXX/c99-variable-length-array.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=149937&r1=149936&r2=149937&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Feb  6 18:15:00 2012
@@ -4636,7 +4636,14 @@
 
 // C++ local classes
 def err_reference_to_local_var_in_enclosing_function : Error<
-  "reference to local variable %0 declared in enclosed function %1">;
+  "reference to local variable %0 declared in enclosing function %1">;
+def err_reference_to_local_var_in_enclosing_block : Error<
+  "reference to local variable %0 declared in enclosing block literal">;
+def err_reference_to_local_var_in_enclosing_lambda : Error<
+  "reference to local variable %0 declared in enclosing lambda expression">;
+def err_reference_to_local_var_in_enclosing_context : Error<
+  "reference to local variable %0 declared in enclosing context">;
+
 def note_local_variable_declared_here : Note<
   "%0 declared here">;
 def err_static_data_member_not_allowed_in_local_class : Error<

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=149937&r1=149936&r2=149937&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Feb  6 18:15:00 2012
@@ -9471,29 +9471,47 @@
 static void
 diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
                                    VarDecl *var, DeclContext *DC) {
+  DeclContext *VarDC = var->getDeclContext();
+
   //  If the parameter still belongs to the translation unit, then
   //  we're actually just using one parameter in the declaration of
   //  the next.
   if (isa<ParmVarDecl>(var) &&
-      isa<TranslationUnitDecl>(var->getDeclContext()))
+      isa<TranslationUnitDecl>(VarDC))
     return;
 
-  // Don't diagnose about capture if we're not actually in code right
-  // now; in general, there are more appropriate places that will
-  // diagnose this.
-  // FIXME: We incorrectly skip diagnosing C++11 member initializers.
-  if (!S.CurContext->isFunctionOrMethod())
+  // For C code, don't diagnose about capture if we're not actually in code
+  // right now; it's impossible to write a non-constant expression outside of
+  // function context, so we'll get other (more useful) diagnostics later.
+  //
+  // For C++, things get a bit more nasty... it would be nice to suppress this
+  // diagnostic for certain cases like using a local variable in an array bound
+  // for a member of a local class, but the correct predicate is not obvious.
+  if (!S.getLangOptions().CPlusPlus && !S.CurContext->isFunctionOrMethod())
     return;
 
-  DeclarationName functionName;
-  if (FunctionDecl *fn = dyn_cast<FunctionDecl>(var->getDeclContext()))
-    functionName = fn->getDeclName();
-  // FIXME: variable from enclosing block that we couldn't capture from!
+  if (isa<CXXMethodDecl>(VarDC) &&
+      cast<CXXRecordDecl>(VarDC->getParent())->isLambda()) {
+    S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_lambda)
+      << var->getIdentifier();
+  } else if (FunctionDecl *fn = dyn_cast<FunctionDecl>(VarDC)) {
+    S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_function)
+      << var->getIdentifier() << fn->getDeclName();
+  } else if (isa<BlockDecl>(VarDC)) {
+    S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_block)
+      << var->getIdentifier();
+  } else {
+    // FIXME: Is there any other context where a local variable can be
+    // declared?
+    S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_context)
+      << var->getIdentifier();
+  }
 
-  S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_function)
-    << var->getIdentifier() << functionName;
   S.Diag(var->getLocation(), diag::note_local_variable_declared_here)
     << var->getIdentifier();
+
+  // FIXME: Add additional diagnostic info about class etc. which prevents
+  // capture.
 }
 
 static bool shouldAddConstForScope(CapturingScopeInfo *CSI, VarDecl *VD) {

Added: cfe/trunk/test/CXX/class/class.local/p1-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.local/p1-0x.cpp?rev=149937&view=auto
==============================================================================
--- cfe/trunk/test/CXX/class/class.local/p1-0x.cpp (added)
+++ cfe/trunk/test/CXX/class/class.local/p1-0x.cpp Mon Feb  6 18:15:00 2012
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s 
+
+void f() {
+  int x = 3; // expected-note{{'x' declared here}}
+  const int c = 2;
+  struct C {
+    int& x2 = x; // expected-error{{reference to local variable 'x' declared in enclosing function 'f'}}
+    int cc = c;
+  };
+  []() mutable { // expected-error {{not supported yet}}
+    int x = 3; // expected-note{{'x' declared here}}
+    struct C {
+      int& x2 = x; // expected-error{{reference to local variable 'x' declared in enclosing lambda expression}}
+    };
+  }
+  C();
+}
+

Modified: cfe/trunk/test/CXX/class/class.local/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.local/p1.cpp?rev=149937&r1=149936&r2=149937&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class/class.local/p1.cpp (original)
+++ cfe/trunk/test/CXX/class/class.local/p1.cpp Mon Feb  6 18:15:00 2012
@@ -8,7 +8,7 @@
   extern int g();
   
   struct local {
-    int g() { return x; } // expected-error{{reference to local variable 'x' declared in enclosed function 'f'}}
+    int g() { return x; } // expected-error{{reference to local variable 'x' declared in enclosing function 'f'}}
     int h() { return s; }
     int k() { return :: x; }
     int l() { return g(); }

Modified: cfe/trunk/test/CXX/class/class.local/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.local/p3.cpp?rev=149937&r1=149936&r2=149937&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class/class.local/p3.cpp (original)
+++ cfe/trunk/test/CXX/class/class.local/p3.cpp Mon Feb  6 18:15:00 2012
@@ -24,7 +24,7 @@
 void f3(int a) { // expected-note{{'a' declared here}}
   struct X {
     struct Y {
-      int f() { return a; } // expected-error{{reference to local variable 'a' declared in enclosed function 'f3'}}
+      int f() { return a; } // expected-error{{reference to local variable 'a' declared in enclosing function 'f3'}}
     };
   };
 }

Modified: cfe/trunk/test/SemaCXX/c99-variable-length-array.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/c99-variable-length-array.cpp?rev=149937&r1=149936&r2=149937&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/c99-variable-length-array.cpp (original)
+++ cfe/trunk/test/SemaCXX/c99-variable-length-array.cpp Mon Feb  6 18:15:00 2012
@@ -73,10 +73,11 @@
 }
 
 // Variably-modified types cannot be used in local classes.
-void local_classes(int N) {
+void local_classes(int N) { // expected-note {{declared here}}
   struct X {
     int size;
     int array[N]; // expected-error{{fields must have a constant size: 'variable length array in structure' extension will never be supported}} \
+                  // expected-error{{reference to local variable 'N' declared in enclosing function 'local_classes'}} \
                   // expected-warning{{variable length arrays are a C99 feature}}
   };
 }





More information about the cfe-commits mailing list