From: Douglas Gregor Date: Fri, 27 May 2011 16:05:29 +0000 (+0000) Subject: Update the jump-scope checker for local variables with initializers, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e413516d0ed61ef9e2ff706bcc00480adca947c4;p=clang Update the jump-scope checker for local variables with initializers, so that it looks at the initializer of a local variable of class type (or array thereof) to determine whether it's just an implicit invocation of the trivial default constructor. Fixes PR10034. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132191 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index 867d78fef6..44ba103fe0 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -15,6 +15,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtCXX.h" #include "llvm/ADT/BitVector.h" @@ -126,18 +127,48 @@ static std::pair InDiag = diag::note_protected_by_cleanup; OutDiag = diag::note_exits_cleanup; } else if (isCPlusPlus) { - // FIXME: In C++0x, we have to check more conditions than "did we - // just give it an initializer?". See 6.7p3. - if (VD->hasLocalStorage() && VD->hasInit()) - InDiag = diag::note_protected_by_variable_init; - - CanQualType T = VD->getType()->getCanonicalTypeUnqualified(); + if (!VD->hasLocalStorage()) + return std::make_pair(InDiag, OutDiag); + + ASTContext &Context = D->getASTContext(); + QualType T = Context.getBaseElementType(VD->getType()); if (!T->isDependentType()) { - while (CanQual AT = T->getAs()) - T = AT->getElementType(); - if (CanQual RT = T->getAs()) - if (!cast(RT->getDecl())->hasTrivialDestructor()) + // C++0x [stmt.dcl]p3: + // A program that jumps from a point where a variable with automatic + // storage duration is not in scope to a point where it is in scope + // is ill-formed unless the variable has scalar type, class type with + // a trivial default constructor and a trivial destructor, a + // cv-qualified version of one of these types, or an array of one of + // the preceding types and is declared without an initializer (8.5). + if (VD->hasLocalStorage() && Context.getLangOptions().CPlusPlus) { + // Check whether this is a C++ class. + CXXRecordDecl *Record = T->getAsCXXRecordDecl(); + + if (const Expr *Init = VD->getInit()) { + bool CallsTrivialConstructor = false; + if (Record) { + // FIXME: With generalized initializer lists, this may + // classify "X x{};" as having no initializer. + if (const CXXConstructExpr *Construct + = dyn_cast(Init)) + if (const CXXConstructorDecl *Constructor + = Construct->getConstructor()) + if (Constructor->isDefaultConstructor() && + ((Context.getLangOptions().CPlusPlus0x && + Record->hasTrivialDefaultConstructor()) || + (!Context.getLangOptions().CPlusPlus0x && + Record->isPOD()))) + CallsTrivialConstructor = true; + } + + if (!CallsTrivialConstructor) + InDiag = diag::note_protected_by_variable_init; + } + + // Note whether we have a class with a non-trivial destructor. + if (Record && !Record->hasTrivialDestructor()) OutDiag = diag::note_exits_dtor; + } } } diff --git a/test/CXX/stmt.stmt/stmt.dcl/p3.cpp b/test/CXX/stmt.stmt/stmt.dcl/p3.cpp new file mode 100644 index 0000000000..2cf745e450 --- /dev/null +++ b/test/CXX/stmt.stmt/stmt.dcl/p3.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +// PR10034 +struct X {}; + +void exx(X) {} + +int main(int argc, char **argv) +{ + if (argc > 3) + goto end; + + X x; + X xs[16]; + exx(x); + + end: + if (argc > 1) { + for (int i = 0; i < argc; ++i) + { + + } + } + return 0; +}