]> granicus.if.org Git - clang/commitdiff
Misc improvements to the diagnostic when a variable is odr-used in a context that...
authorEli Friedman <eli.friedman@gmail.com>
Tue, 7 Feb 2012 00:15:00 +0000 (00:15 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Tue, 7 Feb 2012 00:15:00 +0000 (00:15 +0000)
Fixes PR11883.

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaExpr.cpp
test/CXX/class/class.local/p1-0x.cpp [new file with mode: 0644]
test/CXX/class/class.local/p1.cpp
test/CXX/class/class.local/p3.cpp
test/SemaCXX/c99-variable-length-array.cpp

index 7eef491e48ae237f4b38fa361a1c1d67fc7d2631..e52b35e1cdc8f344beded1e6821aa16495376e45 100644 (file)
@@ -4636,7 +4636,14 @@ def ext_ms_anonymous_struct : ExtWarn<
 
 // 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<
index 8afe0c25b9efe212bd4b8f902511906ab5fc8112..c21979758d3018e46cefbaff5d9d614c746e0441 100644 (file)
@@ -9471,29 +9471,47 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
 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) {
diff --git a/test/CXX/class/class.local/p1-0x.cpp b/test/CXX/class/class.local/p1-0x.cpp
new file mode 100644 (file)
index 0000000..8916295
--- /dev/null
@@ -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();
+}
+
index 05ae5c71d15a984630fa1d362c96f91ee3c73638..62ade5cb8846195e1b934f3b49f13ca33598cb2f 100644 (file)
@@ -8,7 +8,7 @@ void f()
   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(); }
index c24d5d8a09a20a5983dbea4578120bec1ccaac07..3753790384962358f6d4db73f9416930dc24cae2 100644 (file)
@@ -24,7 +24,7 @@ void f2() {
 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'}}
     };
   };
 }
index 2f9bb957ec0570ebb03d88fa8a67615427c3af4b..7773c0849b4af606655771f57da3b6105100a062 100644 (file)
@@ -73,10 +73,11 @@ void test_accept_array(int N) {
 }
 
 // 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}}
   };
 }