[cfe-commits] r110063 - in /cfe/trunk: include/clang/AST/Expr.h lib/AST/Expr.cpp lib/Checker/CheckDeadStores.cpp lib/CodeGen/CGDecl.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp test/SemaCXX/warn-global-constructors.cpp
John McCall
rjmccall at apple.com
Mon Aug 2 14:13:48 PDT 2010
Author: rjmccall
Date: Mon Aug 2 16:13:48 2010
New Revision: 110063
URL: http://llvm.org/viewvc/llvm-project?rev=110063&view=rev
Log:
Further adjustments to -Wglobal-constructors; works for references and direct
initializations now.
Modified:
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/lib/AST/Expr.cpp
cfe/trunk/lib/Checker/CheckDeadStores.cpp
cfe/trunk/lib/CodeGen/CGDecl.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/test/SemaCXX/warn-global-constructors.cpp
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=110063&r1=110062&r2=110063&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Mon Aug 2 16:13:48 2010
@@ -309,7 +309,7 @@
}
/// 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, bool ForRef) const;
/// EvalResult is a struct with detailed info about an evaluated expression.
struct EvalResult {
Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=110063&r1=110062&r2=110063&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Mon Aug 2 16:13:48 2010
@@ -1342,15 +1342,20 @@
return false;
}
-bool Expr::isConstantInitializer(ASTContext &Ctx) const {
+bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
// This function is attempting whether an expression is an initializer
// which can be evaluated at compile-time. isEvaluatable handles most
// of the cases, but it can't deal with some initializer-specific
// expressions, and it can't deal with aggregates; we deal with those here,
// and fall back to isEvaluatable for the other cases.
- // FIXME: This function assumes the variable being assigned to
- // isn't a reference type!
+ // If we ever capture reference-binding directly in the AST, we can
+ // kill the second parameter.
+
+ if (IsForRef) {
+ EvalResult Result;
+ return EvaluateAsLValue(Result, Ctx) && !Result.HasSideEffects;
+ }
switch (getStmtClass()) {
default: break;
@@ -1361,23 +1366,24 @@
case CXXTemporaryObjectExprClass:
case CXXConstructExprClass: {
const CXXConstructExpr *CE = cast<CXXConstructExpr>(this);
+
+ // Only if it's
+ // 1) an application of the trivial default constructor or
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);
+ if (!CE->getNumArgs()) return true;
+
+ // 2) an elidable trivial copy construction of an operand which is
+ // itself a constant initializer. Note that we consider the
+ // operand on its own, *not* as a reference binding.
+ return CE->isElidable() &&
+ CE->getArg(0)->isConstantInitializer(Ctx, false);
}
case CompoundLiteralExprClass: {
// This handles gcc's extension that allows global initializers like
// "struct x {int x;} x = (struct x) {};".
// FIXME: This accepts other cases it shouldn't!
const Expr *Exp = cast<CompoundLiteralExpr>(this)->getInitializer();
- return Exp->isConstantInitializer(Ctx);
+ return Exp->isConstantInitializer(Ctx, false);
}
case InitListExprClass: {
// FIXME: This doesn't deal with fields with reference types correctly.
@@ -1386,7 +1392,7 @@
const InitListExpr *Exp = cast<InitListExpr>(this);
unsigned numInits = Exp->getNumInits();
for (unsigned i = 0; i < numInits; i++) {
- if (!Exp->getInit(i)->isConstantInitializer(Ctx))
+ if (!Exp->getInit(i)->isConstantInitializer(Ctx, false))
return false;
}
return true;
@@ -1394,11 +1400,12 @@
case ImplicitValueInitExprClass:
return true;
case ParenExprClass:
- return cast<ParenExpr>(this)->getSubExpr()->isConstantInitializer(Ctx);
+ return cast<ParenExpr>(this)->getSubExpr()
+ ->isConstantInitializer(Ctx, IsForRef);
case UnaryOperatorClass: {
const UnaryOperator* Exp = cast<UnaryOperator>(this);
if (Exp->getOpcode() == UnaryOperator::Extension)
- return Exp->getSubExpr()->isConstantInitializer(Ctx);
+ return Exp->getSubExpr()->isConstantInitializer(Ctx, false);
break;
}
case BinaryOperatorClass: {
@@ -1411,6 +1418,7 @@
return true;
break;
}
+ case CXXFunctionalCastExprClass:
case CXXStaticCastExprClass:
case ImplicitCastExprClass:
case CStyleCastExprClass:
@@ -1418,13 +1426,15 @@
// deals with both the gcc no-op struct cast extension and the
// cast-to-union extension.
if (getType()->isRecordType())
- return cast<CastExpr>(this)->getSubExpr()->isConstantInitializer(Ctx);
+ return cast<CastExpr>(this)->getSubExpr()
+ ->isConstantInitializer(Ctx, false);
// Integer->integer casts can be handled here, which is important for
// things like (int)(&&x-&&y). Scary but true.
if (getType()->isIntegerType() &&
cast<CastExpr>(this)->getSubExpr()->getType()->isIntegerType())
- return cast<CastExpr>(this)->getSubExpr()->isConstantInitializer(Ctx);
+ return cast<CastExpr>(this)->getSubExpr()
+ ->isConstantInitializer(Ctx, false);
break;
}
Modified: cfe/trunk/lib/Checker/CheckDeadStores.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CheckDeadStores.cpp?rev=110063&r1=110062&r2=110063&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/CheckDeadStores.cpp (original)
+++ cfe/trunk/lib/Checker/CheckDeadStores.cpp Mon Aug 2 16:13:48 2010
@@ -217,7 +217,7 @@
// If x is EVER assigned a new value later, don't issue
// a warning. This is because such initialization can be
// due to defensive programming.
- if (E->isConstantInitializer(Ctx))
+ if (E->isConstantInitializer(Ctx, false))
return;
if (DeclRefExpr *DRE=dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=110063&r1=110062&r2=110063&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Mon Aug 2 16:13:48 2010
@@ -512,10 +512,10 @@
// If this value is an array or struct, is POD, and if the initializer is
// a staticly determinable constant, try to optimize it (unless the NRVO
// is already optimizing this).
- if (D.getInit() && !isByRef &&
+ if (!NRVO && D.getInit() && !isByRef &&
(Ty->isArrayType() || Ty->isRecordType()) &&
Ty->isPODType() &&
- D.getInit()->isConstantInitializer(getContext()) && !NRVO) {
+ D.getInit()->isConstantInitializer(getContext(), false)) {
// If this variable is marked 'const', emit the value as a global.
if (CGM.getCodeGenOpts().MergeAllConstants &&
Ty.isConstant(getContext())) {
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=110063&r1=110062&r2=110063&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Aug 2 16:13:48 2010
@@ -3855,7 +3855,7 @@
// "may accept other forms of constant expressions" exception.
// (We never end up here for C++, so the constant expression
// rules there don't matter.)
- if (Init->isConstantInitializer(Context))
+ if (Init->isConstantInitializer(Context, false))
return false;
Diag(Init->getExprLoc(), diag::err_init_element_not_constant)
<< Init->getSourceRange();
@@ -4067,8 +4067,11 @@
if (getLangOptions().CPlusPlus) {
if (!VDecl->isInvalidDecl() &&
!VDecl->getDeclContext()->isDependentContext() &&
- VDecl->hasGlobalStorage() && !Init->isConstantInitializer(Context))
- Diag(VDecl->getLocation(), diag::warn_global_constructor);
+ VDecl->hasGlobalStorage() &&
+ !Init->isConstantInitializer(Context,
+ VDecl->getType()->isReferenceType()))
+ Diag(VDecl->getLocation(), diag::warn_global_constructor)
+ << Init->getSourceRange();
// Make sure we mark the destructor as used if necessary.
QualType InitType = VDecl->getType();
@@ -4281,7 +4284,7 @@
if (getLangOptions().CPlusPlus && !Var->isInvalidDecl() &&
Var->hasGlobalStorage() &&
!Var->getDeclContext()->isDependentContext() &&
- !Var->getInit()->isConstantInitializer(Context))
+ !Var->getInit()->isConstantInitializer(Context, false))
Diag(Var->getLocation(), diag::warn_global_constructor);
}
}
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=110063&r1=110062&r2=110063&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Aug 2 16:13:48 2010
@@ -5461,6 +5461,14 @@
VDecl->setInit(Result.takeAs<Expr>());
VDecl->setCXXDirectInitializer(true);
+ if (!VDecl->isInvalidDecl() &&
+ !VDecl->getDeclContext()->isDependentContext() &&
+ VDecl->hasGlobalStorage() &&
+ !VDecl->getInit()->isConstantInitializer(Context,
+ VDecl->getType()->isReferenceType()))
+ Diag(VDecl->getLocation(), diag::warn_global_constructor)
+ << VDecl->getInit()->getSourceRange();
+
if (const RecordType *Record = VDecl->getType()->getAs<RecordType>())
FinalizeVarWithDestructor(VDecl, Record);
}
Modified: cfe/trunk/test/SemaCXX/warn-global-constructors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-global-constructors.cpp?rev=110063&r1=110062&r2=110063&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-global-constructors.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-global-constructors.cpp Mon Aug 2 16:13:48 2010
@@ -22,6 +22,11 @@
A b = A();
A c = { 10 };
A d = { opaque_int() }; // expected-warning {{global constructor}}
+ A e = A(A());
+ A f = A(a); // expected-warning {{global constructor}}
+ A g(a); // expected-warning {{global constructor}}
+ A h((A())); // expected-warning {{global constructor}}
+ A i((A(A()))); // expected-warning {{global constructor}}
}
namespace test2 {
@@ -30,10 +35,9 @@
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}}
+ A &d = a;
+ A &e = b[5];
+ A &f = c[5][7];
}
namespace test3 {
@@ -42,10 +46,9 @@
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}}
+ A &d = a;
+ A &e = b[5];
+ A &f = c[5][7];
}
namespace test4 {
More information about the cfe-commits
mailing list