Kill off RequiresGlobalConstructor in favor of isConstantInitializer.

Note some obvious false positives in the test case.

llvm-svn: 109986
This commit is contained in:
John McCall 2010-08-01 21:51:45 +00:00
parent 1b2bc1b844
commit 81c9cea24b
4 changed files with 34 additions and 54 deletions

View File

@ -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 {

View File

@ -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

View File

@ -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);
}
}

View File

@ -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" };
}