diff options
author | Rafael Espindola <rafael.espindola@gmail.com> | 2012-10-27 01:17:42 +0000 |
---|---|---|
committer | Rafael Espindola <rafael.espindola@gmail.com> | 2012-10-27 01:17:42 +0000 |
commit | c5f9943a60112a634c0bb10dfad1c17c75601488 (patch) | |
tree | ad79acc55a2f612fe93333825b036601c152c677 | |
parent | 3ee56a3bf5a2ea8f669f9f8d8530644851a21f21 (diff) | |
download | bcm5719-llvm-c5f9943a60112a634c0bb10dfad1c17c75601488.tar.gz bcm5719-llvm-c5f9943a60112a634c0bb10dfad1c17c75601488.zip |
Fix cases where we were not producing an error when a computed goto could
jump over destructor calls.
Fixes pr13812.
llvm-svn: 166855
-rw-r--r-- | clang/lib/Sema/JumpDiagnostics.cpp | 76 | ||||
-rw-r--r-- | clang/test/SemaCXX/scope-check.cpp | 58 |
2 files changed, 99 insertions, 35 deletions
diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp index a48779a1c36..b920a43de7e 100644 --- a/clang/lib/Sema/JumpDiagnostics.cpp +++ b/clang/lib/Sema/JumpDiagnostics.cpp @@ -123,7 +123,7 @@ typedef std::pair<unsigned,unsigned> ScopePair; /// 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 @@ static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) { // 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)) { diff --git a/clang/test/SemaCXX/scope-check.cpp b/clang/test/SemaCXX/scope-check.cpp index 86d1bd8960f..78228c0dc5f 100644 --- a/clang/test/SemaCXX/scope-check.cpp +++ b/clang/test/SemaCXX/scope-check.cpp @@ -202,3 +202,61 @@ namespace test10 { 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; + } +} |