Kill off RequiresGlobalConstructor in favor of isConstantInitializer.
Note some obvious false positives in the test case. llvm-svn: 109986
This commit is contained in:
parent
1b2bc1b844
commit
81c9cea24b
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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" };
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue