Skip to content

Commit 81c9cea

Browse files
committed
Kill off RequiresGlobalConstructor in favor of isConstantInitializer.
Note some obvious false positives in the test case. llvm-svn: 109986
1 parent 1b2bc1b commit 81c9cea

File tree

4 files changed

+34
-54
lines changed

4 files changed

+34
-54
lines changed

clang/include/clang/AST/Expr.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ class Expr : public Stmt {
309309
}
310310
/// isConstantInitializer - Returns true if this expression is a constant
311311
/// initializer, which can be emitted at compile-time.
312-
bool isConstantInitializer(ASTContext &Ctx) const;
312+
bool isConstantInitializer(ASTContext &Ctx) const;
313313

314314
/// EvalResult is a struct with detailed info about an evaluated expression.
315315
struct EvalResult {

clang/lib/AST/Expr.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,6 +1358,20 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const {
13581358
case ObjCStringLiteralClass:
13591359
case ObjCEncodeExprClass:
13601360
return true;
1361+
case CXXTemporaryObjectExprClass:
1362+
case CXXConstructExprClass: {
1363+
const CXXConstructExpr *CE = cast<CXXConstructExpr>(this);
1364+
if (!CE->getConstructor()->isTrivial()) return false;
1365+
for (CXXConstructExpr::const_arg_iterator
1366+
I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I)
1367+
if (!(*I)->isConstantInitializer(Ctx))
1368+
return false;
1369+
return true;
1370+
}
1371+
case CXXBindReferenceExprClass: {
1372+
const CXXBindReferenceExpr *RE = cast<CXXBindReferenceExpr>(this);
1373+
return RE->getSubExpr()->isConstantInitializer(Ctx);
1374+
}
13611375
case CompoundLiteralExprClass: {
13621376
// This handles gcc's extension that allows global initializers like
13631377
// "struct x {int x;} x = (struct x) {};".
@@ -1397,6 +1411,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const {
13971411
return true;
13981412
break;
13991413
}
1414+
case CXXStaticCastExprClass:
14001415
case ImplicitCastExprClass:
14011416
case CStyleCastExprClass:
14021417
// Handle casts with a destination that's a struct or union; this

clang/lib/Sema/SemaDecl.cpp

Lines changed: 2 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3866,57 +3866,6 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init) {
38663866
AddInitializerToDecl(dcl, move(init), /*DirectInit=*/false);
38673867
}
38683868

3869-
/// Make a reasonable guess at whether the given initializer will
3870-
/// require a global constructor.
3871-
static bool RequiresGlobalConstructor(Sema &S, Expr *Init) {
3872-
// FIXME: reproducing the logic of CGExprConstant is kindof dumb.
3873-
// Maybe this should be integrated into the constant-evaluator?
3874-
// We'd need array and struct value types.
3875-
//
3876-
// It's probably okay to still warn in the theoretical cases where
3877-
// IR gen can eliminate a global constructor based on
3878-
// initialization order (not that it actually does that
3879-
// optimization at the moment).
3880-
if (Init->isEvaluatable(S.Context)) return false;
3881-
3882-
Init = Init->IgnoreParenNoopCasts(S.Context);
3883-
3884-
// Look through reference-bindings.
3885-
if (CXXBindReferenceExpr *BE = dyn_cast<CXXBindReferenceExpr>(Init))
3886-
return RequiresGlobalConstructor(S, BE);
3887-
3888-
// A constructor call needs a global constructor if:
3889-
if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init)) {
3890-
// - the constructor is non-trivial
3891-
if (!CE->getConstructor()->isTrivial()) return true;
3892-
3893-
// - any of the argument expressions needs a global constructor
3894-
for (CXXConstructExpr::arg_iterator
3895-
I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I)
3896-
if (RequiresGlobalConstructor(S, *I))
3897-
return true;
3898-
3899-
// We don't have to worry about building temporaries with
3900-
// non-trivial destructors because we should never have walked
3901-
// through the CXXExprWithTemporaries.
3902-
3903-
// So it should be emitted as a constant expression.
3904-
return false;
3905-
}
3906-
3907-
/// An initializer list requires a global constructor if any of the
3908-
/// components do.
3909-
if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
3910-
for (unsigned I = 0, E = ILE->getNumInits(); I != E; ++I)
3911-
if (RequiresGlobalConstructor(S, ILE->getInit(I)))
3912-
return true;
3913-
return false;
3914-
}
3915-
3916-
// Assume everything else does.
3917-
return true;
3918-
}
3919-
39203869
/// AddInitializerToDecl - Adds the initializer Init to the
39213870
/// declaration dcl. If DirectInit is true, this is C++ direct
39223871
/// initialization rather than copy initialization.
@@ -4118,7 +4067,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
41184067
if (getLangOptions().CPlusPlus) {
41194068
if (!VDecl->isInvalidDecl() &&
41204069
!VDecl->getDeclContext()->isDependentContext() &&
4121-
VDecl->hasGlobalStorage() && RequiresGlobalConstructor(*this, Init))
4070+
VDecl->hasGlobalStorage() && !Init->isConstantInitializer(Context))
41224071
Diag(VDecl->getLocation(), diag::warn_global_constructor);
41234072

41244073
// Make sure we mark the destructor as used if necessary.
@@ -4332,7 +4281,7 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl,
43324281
if (getLangOptions().CPlusPlus && !Var->isInvalidDecl() &&
43334282
Var->hasGlobalStorage() &&
43344283
!Var->getDeclContext()->isDependentContext() &&
4335-
RequiresGlobalConstructor(*this, Var->getInit()))
4284+
!Var->getInit()->isConstantInitializer(Context))
43364285
Diag(Var->getLocation(), diag::warn_global_constructor);
43374286
}
43384287
}

clang/test/SemaCXX/warn-global-constructors.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,27 @@ namespace test2 {
2929
A a; // expected-warning {{global constructor}}
3030
A b[10]; // expected-warning {{global constructor}}
3131
A c[10][10]; // expected-warning {{global constructor}}
32+
33+
// FIXME: false positives!
34+
A &d = a; // expected-warning {{global constructor}}
35+
A &e = b[5]; // expected-warning {{global constructor}}
36+
A &f = c[5][7]; // expected-warning {{global constructor}}
3237
}
3338

3439
namespace test3 {
3540
struct A { ~A(); };
3641
A a; // expected-warning {{global destructor}}
3742
A b[10]; // expected-warning {{global destructor}}
3843
A c[10][10]; // expected-warning {{global destructor}}
44+
45+
// FIXME: false positives!
46+
A &d = a; // expected-warning {{global constructor}}
47+
A &e = b[5]; // expected-warning {{global constructor}}
48+
A &f = c[5][7]; // expected-warning {{global constructor}}
49+
}
50+
51+
namespace test4 {
52+
char a[] = "hello";
53+
char b[5] = "hello";
54+
char c[][5] = { "hello" };
3955
}

0 commit comments

Comments
 (0)