From 8b0f4ff317be790b964821fd1ab854e3398dcc0c Mon Sep 17 00:00:00 2001 From: John McCall Date: Mon, 2 Aug 2010 21:13:48 +0000 Subject: Further adjustments to -Wglobal-constructors; works for references and direct initializations now. llvm-svn: 110063 --- clang/lib/AST/Expr.cpp | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) (limited to 'clang/lib/AST/Expr.cpp') diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index a36a83ba99f..7642c0de2cb 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1342,15 +1342,20 @@ bool Expr::hasAnyValueDependentArguments(Expr** Exprs, unsigned NumExprs) { 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 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { case CXXTemporaryObjectExprClass: case CXXConstructExprClass: { const CXXConstructExpr *CE = cast(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(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(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 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { const InitListExpr *Exp = cast(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 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { case ImplicitValueInitExprClass: return true; case ParenExprClass: - return cast(this)->getSubExpr()->isConstantInitializer(Ctx); + return cast(this)->getSubExpr() + ->isConstantInitializer(Ctx, IsForRef); case UnaryOperatorClass: { const UnaryOperator* Exp = cast(this); if (Exp->getOpcode() == UnaryOperator::Extension) - return Exp->getSubExpr()->isConstantInitializer(Ctx); + return Exp->getSubExpr()->isConstantInitializer(Ctx, false); break; } case BinaryOperatorClass: { @@ -1411,6 +1418,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { return true; break; } + case CXXFunctionalCastExprClass: case CXXStaticCastExprClass: case ImplicitCastExprClass: case CStyleCastExprClass: @@ -1418,13 +1426,15 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { // deals with both the gcc no-op struct cast extension and the // cast-to-union extension. if (getType()->isRecordType()) - return cast(this)->getSubExpr()->isConstantInitializer(Ctx); + return cast(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(this)->getSubExpr()->getType()->isIntegerType()) - return cast(this)->getSubExpr()->isConstantInitializer(Ctx); + return cast(this)->getSubExpr() + ->isConstantInitializer(Ctx, false); break; } -- cgit v1.2.3