aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-08-01 21:51:45 +0000
committerJohn McCall <rjmccall@apple.com>2010-08-01 21:51:45 +0000
commitb4b9b15c597a923a03ad0a33cdc49b67e5cc4450 (patch)
tree953044712bdb5e7d65a55208989e9be5e2823579
parent626e96e2874698a6736fd33672fa9c28da91d77e (diff)
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
-rw-r--r--include/clang/AST/Expr.h2
-rw-r--r--lib/AST/Expr.cpp15
-rw-r--r--lib/Sema/SemaDecl.cpp55
-rw-r--r--test/SemaCXX/warn-global-constructors.cpp16
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<CXXConstructExpr>(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<CXXBindReferenceExpr>(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<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.
@@ -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" };
}