diff options
author | Richard Smith <richard@metafoo.co.uk> | 2020-02-06 16:19:37 -0800 |
---|---|---|
committer | Richard Smith <richard@metafoo.co.uk> | 2020-02-06 16:37:22 -0800 |
commit | 96c899449b61b866b583560a49c4627f561336fc (patch) | |
tree | ea3692e14e45cc4798dd3de3be8009adf04b18ce /clang/lib/AST/ExprConstant.cpp | |
parent | 3e5d837cdabca5a7f0e965fa454b169bdd45b06a (diff) | |
download | llvm-96c899449b61b866b583560a49c4627f561336fc.zip llvm-96c899449b61b866b583560a49c4627f561336fc.tar.gz llvm-96c899449b61b866b583560a49c4627f561336fc.tar.bz2 |
C++ DR2026: static storage duration variables are not zeroed before
constant initialization.
Removing this zeroing regressed our code generation in a few cases, also
fixed here. We now compute whether a variable has constant destruction
even if it doesn't have a constant initializer, by trying to destroy a
default-initialized value, and skip emitting a trivial default
constructor for a variable even if it has non-trivial (but perhaps
constant) destruction.
Diffstat (limited to 'clang/lib/AST/ExprConstant.cpp')
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 37 |
1 files changed, 15 insertions, 22 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 860eeb1..dfa9444 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -5609,9 +5609,14 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, } // Reserve space for the struct members. - if (!RD->isUnion() && !Result.hasValue()) - Result = APValue(APValue::UninitStruct(), RD->getNumBases(), - std::distance(RD->field_begin(), RD->field_end())); + if (!Result.hasValue()) { + if (!RD->isUnion()) + Result = APValue(APValue::UninitStruct(), RD->getNumBases(), + std::distance(RD->field_begin(), RD->field_end())); + else + // A union starts with no active member. + Result = APValue((const FieldDecl*)nullptr); + } if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); @@ -13909,18 +13914,6 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, LValue LVal; LVal.set(VD); - // C++11 [basic.start.init]p2: - // Variables with static storage duration or thread storage duration shall - // be zero-initialized before any other initialization takes place. - // This behavior is not present in C. - if (Ctx.getLangOpts().CPlusPlus && !VD->hasLocalStorage() && - !DeclTy->isReferenceType()) { - ImplicitValueInitExpr VIE(DeclTy); - if (!EvaluateInPlace(Value, Info, LVal, &VIE, - /*AllowNonLiteralTypes=*/true)) - return false; - } - if (!EvaluateInPlace(Value, Info, LVal, this, /*AllowNonLiteralTypes=*/true) || EStatus.HasSideEffects) @@ -13939,14 +13932,16 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, bool VarDecl::evaluateDestruction( SmallVectorImpl<PartialDiagnosticAt> &Notes) const { - assert(getEvaluatedValue() && !getEvaluatedValue()->isAbsent() && - "cannot evaluate destruction of non-constant-initialized variable"); - Expr::EvalStatus EStatus; EStatus.Diag = &Notes; - // Make a copy of the value for the destructor to mutate. - APValue DestroyedValue = *getEvaluatedValue(); + // Make a copy of the value for the destructor to mutate, if we know it. + // Otherwise, treat the value as default-initialized; if the destructor works + // anyway, then the destruction is constant (and must be essentially empty). + APValue DestroyedValue = + (getEvaluatedValue() && !getEvaluatedValue()->isAbsent()) + ? *getEvaluatedValue() + : getDefaultInitValue(getType()); EvalInfo Info(getASTContext(), EStatus, EvalInfo::EM_ConstantExpression); Info.setEvaluatingDecl(this, DestroyedValue, @@ -13959,8 +13954,6 @@ bool VarDecl::evaluateDestruction( LValue LVal; LVal.set(this); - // FIXME: Consider storing whether this variable has constant destruction in - // the EvaluatedStmt so that CodeGen can query it. if (!HandleDestruction(Info, DeclLoc, LVal.Base, DestroyedValue, DeclTy) || EStatus.HasSideEffects) return false; |