From: Eli Friedman Date: Tue, 16 Jul 2013 22:40:53 +0000 (+0000) Subject: Make Expr::isConstantInitializer match IRGen. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=21cde050b64eefbb5094af67985752eee42d00e2;p=clang Make Expr::isConstantInitializer match IRGen. Sema needs to be able to accurately determine what will be emitted as a constant initializer and what will not, so we get accurate errors in C and accurate -Wglobal-constructors warnings in C++. This makes Expr::isConstantInitializer match CGExprConstant as closely as possible. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186464 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index c4be32ea70..2e45962646 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -2634,11 +2634,11 @@ bool Expr::hasAnyTypeDependentArguments(ArrayRef Exprs) { 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. - + // which can be evaluated at compile-time. It very closely parallels + // ConstExprEmitter in CGExprConstant.cpp; if they don't match, it + // will lead to unexpected results. Like ConstExprEmitter, it falls back + // to isEvaluatable most of the time. + // // If we ever capture reference-binding directly in the AST, we can // kill the second parameter. @@ -2649,30 +2649,23 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { switch (getStmtClass()) { default: break; - case IntegerLiteralClass: - case FloatingLiteralClass: case StringLiteralClass: - case ObjCStringLiteralClass: case ObjCEncodeExprClass: return true; case CXXTemporaryObjectExprClass: case CXXConstructExprClass: { const CXXConstructExpr *CE = cast(this); - // Only if it's - if (CE->getConstructor()->isTrivial()) { - // 1) an application of the trivial default constructor or + if (CE->getConstructor()->isTrivial() && + CE->getConstructor()->getParent()->hasTrivialDestructor()) { + // Trivial default constructor 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. - if (CE->isElidable() && - CE->getArg(0)->isConstantInitializer(Ctx, false)) - return true; + // Trivial copy constructor + assert(CE->getNumArgs() == 1 && "trivial ctor with > 1 argument"); + return CE->getArg(0)->isConstantInitializer(Ctx, false); } - // 3) a foldable constexpr constructor. break; } case CompoundLiteralExprClass: { @@ -2686,13 +2679,47 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { // FIXME: This doesn't deal with fields with reference types correctly. // FIXME: This incorrectly allows pointers cast to integers to be assigned // to bitfields. - const InitListExpr *Exp = cast(this); - unsigned numInits = Exp->getNumInits(); - for (unsigned i = 0; i < numInits; i++) { - if (!Exp->getInit(i)->isConstantInitializer(Ctx, false)) - return false; + const InitListExpr *ILE = cast(this); + if (ILE->getType()->isArrayType()) { + unsigned numInits = ILE->getNumInits(); + for (unsigned i = 0; i < numInits; i++) { + if (!ILE->getInit(i)->isConstantInitializer(Ctx, false)) + return false; + } + return true; } - return true; + + if (ILE->getType()->isRecordType()) { + unsigned ElementNo = 0; + RecordDecl *RD = ILE->getType()->getAs()->getDecl(); + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { + // If this is a union, skip all the fields that aren't being initialized. + if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field) + continue; + + // Don't emit anonymous bitfields, they just affect layout. + if (Field->isUnnamedBitfield()) + continue; + + if (ElementNo < ILE->getNumInits()) { + const Expr *Elt = ILE->getInit(ElementNo++); + if (Field->isBitField()) { + // Bitfields have to evaluate to an integer. + llvm::APSInt ResultTmp; + if (!Elt->EvaluateAsInt(ResultTmp, Ctx)) + return false; + } else { + bool RefType = Field->getType()->isReferenceType(); + if (!Elt->isConstantInitializer(Ctx, RefType)) + return false; + } + } + } + return true; + } + + break; } case ImplicitValueInitExprClass: return true; @@ -2700,8 +2727,6 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { return cast(this)->getSubExpr() ->isConstantInitializer(Ctx, IsForRef); case GenericSelectionExprClass: - if (cast(this)->isResultDependent()) - return false; return cast(this)->getResultExpr() ->isConstantInitializer(Ctx, IsForRef); case ChooseExprClass: @@ -2716,31 +2741,20 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { case CXXFunctionalCastExprClass: case CXXStaticCastExprClass: case ImplicitCastExprClass: - case CStyleCastExprClass: { + case CStyleCastExprClass: + case ObjCBridgedCastExprClass: + case CXXDynamicCastExprClass: + case CXXReinterpretCastExprClass: + case CXXConstCastExprClass: { const CastExpr *CE = cast(this); - // If we're promoting an integer to an _Atomic type then this is constant - // if the integer is constant. We also need to check the converse in case - // someone does something like: - // - // int a = (_Atomic(int))42; - // - // I doubt anyone would write code like this directly, but it's quite - // possible as the result of macro expansions. - if (CE->getCastKind() == CK_NonAtomicToAtomic || - CE->getCastKind() == CK_AtomicToNonAtomic) - return CE->getSubExpr()->isConstantInitializer(Ctx, false); - - // Handle bitcasts of vector constants. - if (getType()->isVectorType() && CE->getCastKind() == CK_BitCast) - return CE->getSubExpr()->isConstantInitializer(Ctx, false); - // Handle misc casts we want to ignore. - // FIXME: Is it really safe to ignore all these? if (CE->getCastKind() == CK_NoOp || CE->getCastKind() == CK_LValueToRValue || CE->getCastKind() == CK_ToUnion || - CE->getCastKind() == CK_ConstructorConversion) + CE->getCastKind() == CK_ConstructorConversion || + CE->getCastKind() == CK_NonAtomicToAtomic || + CE->getCastKind() == CK_AtomicToNonAtomic) return CE->getSubExpr()->isConstantInitializer(Ctx, false); break; @@ -2748,6 +2762,16 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { case MaterializeTemporaryExprClass: return cast(this)->GetTemporaryExpr() ->isConstantInitializer(Ctx, false); + + case SubstNonTypeTemplateParmExprClass: + return cast(this)->getReplacement() + ->isConstantInitializer(Ctx, false); + case CXXDefaultArgExprClass: + return cast(this)->getExpr() + ->isConstantInitializer(Ctx, false); + case CXXDefaultInitExprClass: + return cast(this)->getExpr() + ->isConstantInitializer(Ctx, false); } return isEvaluatable(Ctx); } diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index c06cf2f1b2..4a6f90a30e 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -609,6 +609,10 @@ public: return Visit(GE->getResultExpr()); } + llvm::Constant *VisitChooseExpr(ChooseExpr *CE) { + return Visit(CE->getChosenSubExpr(CGM.getContext())); + } + llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { return Visit(E->getInitializer()); } @@ -654,6 +658,7 @@ public: case CK_AtomicToNonAtomic: case CK_NonAtomicToAtomic: case CK_NoOp: + case CK_ConstructorConversion: return C; case CK_Dependent: llvm_unreachable("saw dependent cast!"); @@ -683,7 +688,6 @@ public: case CK_LValueBitCast: case CK_NullToMemberPointer: case CK_UserDefinedConversion: - case CK_ConstructorConversion: case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 8e81866665..bfd880a7e3 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -2958,7 +2958,7 @@ static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E, E = E->IgnoreParens(); // Anything that is an integer or floating point constant is fine. - if (E->isConstantInitializer(CGF.getContext(), false)) + if (E->isEvaluatable(CGF.getContext())) return true; // Non-volatile automatic variables too, to get "cond ? X : Y" where diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 38de4db8ae..e0dab1c4f1 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -8305,10 +8305,16 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { if (IsGlobal && !var->isConstexpr() && getDiagnostics().getDiagnosticLevel(diag::warn_global_constructor, var->getLocation()) - != DiagnosticsEngine::Ignored && - !Init->isConstantInitializer(Context, baseType->isReferenceType())) - Diag(var->getLocation(), diag::warn_global_constructor) - << Init->getSourceRange(); + != DiagnosticsEngine::Ignored) { + // Warn about globals which don't have a constant initializer. Don't + // warn about globals with a non-trivial destructor because we already + // warned about them. + CXXRecordDecl *RD = baseType->getAsCXXRecordDecl(); + if (!(RD && !RD->hasTrivialDestructor()) && + !Init->isConstantInitializer(Context, baseType->isReferenceType())) + Diag(var->getLocation(), diag::warn_global_constructor) + << Init->getSourceRange(); + } if (var->isConstexpr()) { SmallVector Notes; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 114d399e81..517afdac1a 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -4622,7 +4622,7 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, LiteralExpr = Result.get(); bool isFileScope = getCurFunctionOrMethodDecl() == 0; - if (isFileScope) { // 6.5.2.5p3 + if (!getLangOpts().CPlusPlus && isFileScope) { // 6.5.2.5p3 if (CheckForConstantInitializer(LiteralExpr, literalType)) return ExprError(); } diff --git a/test/Sema/init.c b/test/Sema/init.c index 81a665dc62..4a5fc558c5 100644 --- a/test/Sema/init.c +++ b/test/Sema/init.c @@ -157,3 +157,6 @@ int PR4386_zed() __attribute((weak)); typedef char strty[10]; struct vortexstruct { strty s; }; struct vortexstruct vortexvar = { "asdf" }; + +typedef struct { uintptr_t x : 2; } StructWithBitfield; +StructWithBitfield bitfieldvar = { (uintptr_t)&bitfieldvar }; // expected-error {{initializer element is not a compile-time constant}} diff --git a/test/SemaCXX/warn-global-constructors.cpp b/test/SemaCXX/warn-global-constructors.cpp index 6330958df7..f57f0de708 100644 --- a/test/SemaCXX/warn-global-constructors.cpp +++ b/test/SemaCXX/warn-global-constructors.cpp @@ -95,3 +95,9 @@ namespace pr8095 { static Bar b; } } + +namespace referencemember { + struct A { int &a; }; + int a; + A b = { a }; +}