|
48 | 48 | #include "clang/AST/OptionalDiagnostic.h" |
49 | 49 | #include "clang/AST/RecordLayout.h" |
50 | 50 | #include "clang/AST/StmtVisitor.h" |
| 51 | +#include "clang/AST/Type.h" |
51 | 52 | #include "clang/AST/TypeLoc.h" |
52 | 53 | #include "clang/Basic/Builtins.h" |
53 | 54 | #include "clang/Basic/DiagnosticSema.h" |
@@ -4534,6 +4535,30 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, |
4534 | 4535 |
|
4535 | 4536 | BaseVal = MTE->getOrCreateValue(false); |
4536 | 4537 | assert(BaseVal && "got reference to unevaluated temporary"); |
| 4538 | + } else if (const CompoundLiteralExpr *CLE = |
| 4539 | + dyn_cast_or_null<CompoundLiteralExpr>(Base)) { |
| 4540 | + // According to GCC info page: |
| 4541 | + // |
| 4542 | + // 6.28 Compound Literals |
| 4543 | + // |
| 4544 | + // As an optimization, G++ sometimes gives array compound literals |
| 4545 | + // longer lifetimes: when the array either appears outside a function or |
| 4546 | + // has a const-qualified type. If foo and its initializer had elements |
| 4547 | + // of type char *const rather than char *, or if foo were a global |
| 4548 | + // variable, the array would have static storage duration. But it is |
| 4549 | + // probably safest just to avoid the use of array compound literals in |
| 4550 | + // C++ code. |
| 4551 | + // |
| 4552 | + // Obey that rule by checking constness for converted array types. |
| 4553 | + if (QualType CLETy = CLE->getType(); CLETy->isArrayType() && |
| 4554 | + !LValType->isArrayType() && |
| 4555 | + !CLETy.isConstant(Info.Ctx)) { |
| 4556 | + Info.FFDiag(E); |
| 4557 | + Info.Note(CLE->getExprLoc(), diag::note_declared_at); |
| 4558 | + return CompleteObject(); |
| 4559 | + } |
| 4560 | + |
| 4561 | + BaseVal = &CLE->getStaticValue(); |
4537 | 4562 | } else { |
4538 | 4563 | if (!IsAccess) |
4539 | 4564 | return CompleteObject(LVal.getLValueBase(), nullptr, BaseType); |
@@ -4599,44 +4624,7 @@ handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, QualType Type, |
4599 | 4624 | WantObjectRepresentation ? AK_ReadObjectRepresentation : AK_Read; |
4600 | 4625 |
|
4601 | 4626 | if (Base && !LVal.getLValueCallIndex() && !Type.isVolatileQualified()) { |
4602 | | - if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) { |
4603 | | - // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the |
4604 | | - // initializer until now for such expressions. Such an expression can't be |
4605 | | - // an ICE in C, so this only matters for fold. |
4606 | | - if (Type.isVolatileQualified()) { |
4607 | | - Info.FFDiag(Conv); |
4608 | | - return false; |
4609 | | - } |
4610 | | - |
4611 | | - APValue Lit; |
4612 | | - if (!Evaluate(Lit, Info, CLE->getInitializer())) |
4613 | | - return false; |
4614 | | - |
4615 | | - // According to GCC info page: |
4616 | | - // |
4617 | | - // 6.28 Compound Literals |
4618 | | - // |
4619 | | - // As an optimization, G++ sometimes gives array compound literals longer |
4620 | | - // lifetimes: when the array either appears outside a function or has a |
4621 | | - // const-qualified type. If foo and its initializer had elements of type |
4622 | | - // char *const rather than char *, or if foo were a global variable, the |
4623 | | - // array would have static storage duration. But it is probably safest |
4624 | | - // just to avoid the use of array compound literals in C++ code. |
4625 | | - // |
4626 | | - // Obey that rule by checking constness for converted array types. |
4627 | | - |
4628 | | - QualType CLETy = CLE->getType(); |
4629 | | - if (CLETy->isArrayType() && !Type->isArrayType()) { |
4630 | | - if (!CLETy.isConstant(Info.Ctx)) { |
4631 | | - Info.FFDiag(Conv); |
4632 | | - Info.Note(CLE->getExprLoc(), diag::note_declared_at); |
4633 | | - return false; |
4634 | | - } |
4635 | | - } |
4636 | | - |
4637 | | - CompleteObject LitObj(LVal.Base, &Lit, Base->getType()); |
4638 | | - return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal, AK); |
4639 | | - } else if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) { |
| 4627 | + if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) { |
4640 | 4628 | // Special-case character extraction so we don't have to construct an |
4641 | 4629 | // APValue for the whole string. |
4642 | 4630 | assert(LVal.Designator.Entries.size() <= 1 && |
@@ -9144,9 +9132,29 @@ bool |
9144 | 9132 | LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { |
9145 | 9133 | assert((!Info.getLangOpts().CPlusPlus || E->isFileScope()) && |
9146 | 9134 | "lvalue compound literal in c++?"); |
9147 | | - // Defer visiting the literal until the lvalue-to-rvalue conversion. We can |
9148 | | - // only see this when folding in C, so there's no standard to follow here. |
9149 | | - return Success(E); |
| 9135 | + APValue *Lit; |
| 9136 | + // If CompountLiteral has static storage, its value can be used outside |
| 9137 | + // this expression. So evaluate it once and store it in ASTContext. |
| 9138 | + if (E->hasStaticStorage()) { |
| 9139 | + Lit = &E->getOrCreateStaticValue(Info.Ctx); |
| 9140 | + Result.set(E); |
| 9141 | + // Reset any previously evaluated state, otherwise evaluation below might |
| 9142 | + // fail. |
| 9143 | + // FIXME: Should we just re-use the previously evaluated value instead? |
| 9144 | + *Lit = APValue(); |
| 9145 | + } else { |
| 9146 | + assert(!Info.getLangOpts().CPlusPlus); |
| 9147 | + Lit = &Info.CurrentCall->createTemporary(E, E->getInitializer()->getType(), |
| 9148 | + ScopeKind::Block, Result); |
| 9149 | + } |
| 9150 | + // FIXME: Evaluating in place isn't always right. We should figure out how to |
| 9151 | + // use appropriate evaluation context here, see |
| 9152 | + // clang/test/AST/static-compound-literals-reeval.cpp for a failure. |
| 9153 | + if (!EvaluateInPlace(*Lit, Info, Result, E->getInitializer())) { |
| 9154 | + *Lit = APValue(); |
| 9155 | + return false; |
| 9156 | + } |
| 9157 | + return true; |
9150 | 9158 | } |
9151 | 9159 |
|
9152 | 9160 | bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { |
|
0 commit comments