[cfe-commits] r166855 - in /cfe/trunk: lib/Sema/JumpDiagnostics.cpp test/SemaCXX/scope-check.cpp

Rafael Espindola rafael.espindola at gmail.com
Fri Oct 26 18:17:42 PDT 2012


Author: rafael
Date: Fri Oct 26 20:17:42 2012
New Revision: 166855

URL: http://llvm.org/viewvc/llvm-project?rev=166855&view=rev
Log:
Fix cases where we were not producing an error when a computed goto could
jump over destructor calls.
Fixes pr13812.

Modified:
    cfe/trunk/lib/Sema/JumpDiagnostics.cpp
    cfe/trunk/test/SemaCXX/scope-check.cpp

Modified: cfe/trunk/lib/Sema/JumpDiagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/JumpDiagnostics.cpp?rev=166855&r1=166854&r2=166855&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/JumpDiagnostics.cpp (original)
+++ cfe/trunk/lib/Sema/JumpDiagnostics.cpp Fri Oct 26 20:17:42 2012
@@ -123,7 +123,7 @@
 /// diagnostic that should be emitted if control goes over it. If not, return 0.
 static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
   if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
-    unsigned InDiag = 0, OutDiag = 0;
+    unsigned InDiag = 0;
     if (VD->getType()->isVariablyModifiedType())
       InDiag = diag::note_protected_by_vla;
 
@@ -164,43 +164,49 @@
       //   where it is in scope is ill-formed unless the variable has
       //   POD type and is declared without an initializer.
 
-      if (const Expr *init = VD->getInit()) {
-        // We actually give variables of record type (or array thereof)
-        // an initializer even if that initializer only calls a trivial
-        // ctor.  Detect that case.
-        // FIXME: With generalized initializer lists, this may
-        // classify "X x{};" as having no initializer.
-        unsigned inDiagToUse = diag::note_protected_by_variable_init;
-
-        const CXXRecordDecl *record = 0;
-
-        if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(init)) {
-          const CXXConstructorDecl *ctor = cce->getConstructor();
-          record = ctor->getParent();
-
-          if (ctor->isTrivial() && ctor->isDefaultConstructor()) {
-            if (!record->hasTrivialDestructor())
-              inDiagToUse = diag::note_protected_by_variable_nontriv_destructor;
-            else if (!record->isPOD())
-              inDiagToUse = diag::note_protected_by_variable_non_pod;
-            else
-              inDiagToUse = 0;
-          }
-        } else if (VD->getType()->isArrayType()) {
-          record = VD->getType()->getBaseElementTypeUnsafe()
-                                ->getAsCXXRecordDecl();
+      const Expr *Init = VD->getInit();
+      if (!Init)
+        return ScopePair(InDiag, 0);
+
+      const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init);
+      if (EWC)
+        Init = EWC->getSubExpr();
+
+      const MaterializeTemporaryExpr *M = NULL;
+      Init = Init->findMaterializedTemporary(M);
+
+      SmallVector<SubobjectAdjustment, 2> Adjustments;
+      Init = Init->skipRValueSubobjectAdjustments(Adjustments);
+
+      const Type *T = Init->getType().getTypePtr();
+      if (T->isArrayType())
+        T = T->getBaseElementTypeUnsafe();
+
+      const CXXRecordDecl *Record = T->getAsCXXRecordDecl();
+      if (!Record)
+        return ScopePair(diag::note_protected_by_variable_init, 0);
+
+      // If we need to call a non trivial destructor for this variable,
+      // record an out diagnostic.
+      unsigned OutDiag = 0;
+      if (!Record->hasTrivialDestructor() && !Init->isGLValue())
+        OutDiag = diag::note_exits_dtor;
+
+      if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(Init)) {
+        const CXXConstructorDecl *ctor = cce->getConstructor();
+        if (ctor->isTrivial() && ctor->isDefaultConstructor()) {
+          if (OutDiag)
+            InDiag = diag::note_protected_by_variable_nontriv_destructor;
+          else if (!Record->isPOD())
+            InDiag = diag::note_protected_by_variable_non_pod;
+          return ScopePair(InDiag, OutDiag);
         }
-
-        if (inDiagToUse)
-          InDiag = inDiagToUse;
-
-        // Also object to indirect jumps which leave scopes with dtors.
-        if (record && !record->hasTrivialDestructor())
-          OutDiag = diag::note_exits_dtor;
       }
+
+      return ScopePair(diag::note_protected_by_variable_init, OutDiag);
     }
-    
-    return ScopePair(InDiag, OutDiag);    
+
+    return ScopePair(InDiag, 0);
   }
 
   if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {

Modified: cfe/trunk/test/SemaCXX/scope-check.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/scope-check.cpp?rev=166855&r1=166854&r2=166855&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/scope-check.cpp (original)
+++ cfe/trunk/test/SemaCXX/scope-check.cpp Fri Oct 26 20:17:42 2012
@@ -202,3 +202,61 @@
     return 0;
   }
 }
+
+// pr13812
+namespace test11 {
+  struct C {
+    C(int x);
+    ~C();
+  };
+  void f(void **ip) {
+    static void *ips[] = { &&l0 };
+  l0:  // expected-note {{possible target of indirect goto}}
+    C c0 = 42; // expected-note {{jump exits scope of variable with non-trivial destructor}}
+    goto *ip; // expected-error {{indirect goto might cross protected scopes}}
+  }
+}
+
+namespace test12 {
+  struct C {
+    C(int x);
+    ~C();
+  };
+  void f(void **ip) {
+    static void *ips[] = { &&l0 };
+    const C c0 = 17;
+  l0: // expected-note {{possible target of indirect goto}}
+    const C &c1 = 42; // expected-note {{jump exits scope of variable with non-trivial destructor}}
+    const C &c2 = c0;
+    goto *ip; // expected-error {{indirect goto might cross protected scopes}}
+  }
+}
+
+namespace test13 {
+  struct C {
+    C(int x);
+    ~C();
+    int i;
+  };
+  void f(void **ip) {
+    static void *ips[] = { &&l0 };
+  l0: // expected-note {{possible target of indirect goto}}
+    const int &c1 = C(1).i; // expected-note {{jump exits scope of variable with non-trivial destructor}}
+    goto *ip;  // expected-error {{indirect goto might cross protected scopes}}
+  }
+}
+
+namespace test14 {
+  struct C {
+    C(int x);
+    ~C();
+    operator int&() const;
+  };
+  void f(void **ip) {
+    static void *ips[] = { &&l0 };
+  l0:
+    // no warning since the C temporary is destructed before the goto.
+    const int &c1 = C(1);
+    goto *ip;
+  }
+}





More information about the cfe-commits mailing list