diff options
author | John McCall <rjmccall@apple.com> | 2010-08-01 20:20:59 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-08-01 20:20:59 +0000 |
commit | 626e96e2874698a6736fd33672fa9c28da91d77e (patch) | |
tree | eda9946bec66ba3c531df90b2ac3eb9045e7d5f0 /lib/Sema/SemaDecl.cpp | |
parent | 1d8d1ccd36888f1120b3a1df9e76f35dc2edb81d (diff) |
Make a first pass at implementing -Wglobal-constructors. I'm worried that this
will end up bizarrely mirroring CGExprConstant, but that might be the hazard of
this feature.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109984 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 65 |
1 files changed, 64 insertions, 1 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index fa09b31457..6ff21fab0a 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3866,6 +3866,57 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init) { AddInitializerToDecl(dcl, move(init), /*DirectInit=*/false); } +/// Make a reasonable guess at whether the given initializer will +/// require a global constructor. +static bool RequiresGlobalConstructor(Sema &S, Expr *Init) { + // FIXME: reproducing the logic of CGExprConstant is kindof dumb. + // Maybe this should be integrated into the constant-evaluator? + // We'd need array and struct value types. + // + // It's probably okay to still warn in the theoretical cases where + // IR gen can eliminate a global constructor based on + // initialization order (not that it actually does that + // optimization at the moment). + if (Init->isEvaluatable(S.Context)) return false; + + Init = Init->IgnoreParenNoopCasts(S.Context); + + // Look through reference-bindings. + if (CXXBindReferenceExpr *BE = dyn_cast<CXXBindReferenceExpr>(Init)) + return RequiresGlobalConstructor(S, BE); + + // A constructor call needs a global constructor if: + if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init)) { + // - the constructor is non-trivial + if (!CE->getConstructor()->isTrivial()) return true; + + // - any of the argument expressions needs a global constructor + for (CXXConstructExpr::arg_iterator + I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) + if (RequiresGlobalConstructor(S, *I)) + return true; + + // We don't have to worry about building temporaries with + // non-trivial destructors because we should never have walked + // through the CXXExprWithTemporaries. + + // So it should be emitted as a constant expression. + return false; + } + + /// An initializer list requires a global constructor if any of the + /// components do. + if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { + for (unsigned I = 0, E = ILE->getNumInits(); I != E; ++I) + if (RequiresGlobalConstructor(S, ILE->getInit(I))) + return true; + return false; + } + + // Assume everything else does. + return true; +} + /// AddInitializerToDecl - Adds the initializer Init to the /// declaration dcl. If DirectInit is true, this is C++ direct /// initialization rather than copy initialization. @@ -4065,6 +4116,11 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { VDecl->setInit(Init); if (getLangOptions().CPlusPlus) { + if (!VDecl->isInvalidDecl() && + !VDecl->getDeclContext()->isDependentContext() && + VDecl->hasGlobalStorage() && RequiresGlobalConstructor(*this, Init)) + Diag(VDecl->getLocation(), diag::warn_global_constructor); + // Make sure we mark the destructor as used if necessary. QualType InitType = VDecl->getType(); while (const ArrayType *Array = Context.getAsArrayType(InitType)) @@ -4270,8 +4326,15 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, MultiExprArg(*this, 0, 0)); if (Init.isInvalid()) Var->setInvalidDecl(); - else if (Init.get()) + else if (Init.get()) { Var->setInit(MaybeCreateCXXExprWithTemporaries(Init.takeAs<Expr>())); + + if (getLangOptions().CPlusPlus && !Var->isInvalidDecl() && + Var->hasGlobalStorage() && + !Var->getDeclContext()->isDependentContext() && + RequiresGlobalConstructor(*this, Var->getInit())) + Diag(Var->getLocation(), diag::warn_global_constructor); + } } if (!Var->isInvalidDecl() && getLangOptions().CPlusPlus && Record) |