From b4b9b15c597a923a03ad0a33cdc49b67e5cc4450 Mon Sep 17 00:00:00 2001 From: John McCall Date: Sun, 1 Aug 2010 21:51:45 +0000 Subject: [PATCH] Kill off RequiresGlobalConstructor in favor of isConstantInitializer. Note some obvious false positives in the test case. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109986 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Expr.h | 2 +- lib/AST/Expr.cpp | 15 +++++++ lib/Sema/SemaDecl.cpp | 55 +---------------------- test/SemaCXX/warn-global-constructors.cpp | 16 +++++++ 4 files changed, 34 insertions(+), 54 deletions(-) diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index ae3452bef8..5f894d324e 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -309,7 +309,7 @@ public: } /// isConstantInitializer - Returns true if this expression is a constant /// initializer, which can be emitted at compile-time. - bool isConstantInitializer(ASTContext &Ctx) const; + bool isConstantInitializer(ASTContext &Ctx) const; /// EvalResult is a struct with detailed info about an evaluated expression. struct EvalResult { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index f91c3d6ba1..a36a83ba99 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1358,6 +1358,20 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { case ObjCStringLiteralClass: case ObjCEncodeExprClass: return true; + case CXXTemporaryObjectExprClass: + case CXXConstructExprClass: { + const CXXConstructExpr *CE = cast(this); + if (!CE->getConstructor()->isTrivial()) return false; + for (CXXConstructExpr::const_arg_iterator + I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) + if (!(*I)->isConstantInitializer(Ctx)) + return false; + return true; + } + case CXXBindReferenceExprClass: { + const CXXBindReferenceExpr *RE = cast(this); + return RE->getSubExpr()->isConstantInitializer(Ctx); + } case CompoundLiteralExprClass: { // This handles gcc's extension that allows global initializers like // "struct x {int x;} x = (struct x) {};". @@ -1397,6 +1411,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { return true; break; } + case CXXStaticCastExprClass: case ImplicitCastExprClass: case CStyleCastExprClass: // Handle casts with a destination that's a struct or union; this diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 6ff21fab0a..71572d89b6 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3866,57 +3866,6 @@ 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(Init)) - return RequiresGlobalConstructor(S, BE); - - // A constructor call needs a global constructor if: - if (CXXConstructExpr *CE = dyn_cast(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(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. @@ -4118,7 +4067,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { if (getLangOptions().CPlusPlus) { if (!VDecl->isInvalidDecl() && !VDecl->getDeclContext()->isDependentContext() && - VDecl->hasGlobalStorage() && RequiresGlobalConstructor(*this, Init)) + VDecl->hasGlobalStorage() && !Init->isConstantInitializer(Context)) Diag(VDecl->getLocation(), diag::warn_global_constructor); // Make sure we mark the destructor as used if necessary. @@ -4332,7 +4281,7 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, if (getLangOptions().CPlusPlus && !Var->isInvalidDecl() && Var->hasGlobalStorage() && !Var->getDeclContext()->isDependentContext() && - RequiresGlobalConstructor(*this, Var->getInit())) + !Var->getInit()->isConstantInitializer(Context)) Diag(Var->getLocation(), diag::warn_global_constructor); } } diff --git a/test/SemaCXX/warn-global-constructors.cpp b/test/SemaCXX/warn-global-constructors.cpp index 6d0709c5b7..c407e407bb 100644 --- a/test/SemaCXX/warn-global-constructors.cpp +++ b/test/SemaCXX/warn-global-constructors.cpp @@ -29,6 +29,11 @@ namespace test2 { A a; // expected-warning {{global constructor}} A b[10]; // expected-warning {{global constructor}} A c[10][10]; // expected-warning {{global constructor}} + + // FIXME: false positives! + A &d = a; // expected-warning {{global constructor}} + A &e = b[5]; // expected-warning {{global constructor}} + A &f = c[5][7]; // expected-warning {{global constructor}} } namespace test3 { @@ -36,4 +41,15 @@ namespace test3 { A a; // expected-warning {{global destructor}} A b[10]; // expected-warning {{global destructor}} A c[10][10]; // expected-warning {{global destructor}} + + // FIXME: false positives! + A &d = a; // expected-warning {{global constructor}} + A &e = b[5]; // expected-warning {{global constructor}} + A &f = c[5][7]; // expected-warning {{global constructor}} +} + +namespace test4 { + char a[] = "hello"; + char b[5] = "hello"; + char c[][5] = { "hello" }; } -- 2.40.0