|
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