aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
authorkadir çetinkaya <kadircet@google.com>2025-07-08 16:00:40 +0200
committerGitHub <noreply@github.com>2025-07-08 16:00:40 +0200
commitf72e53f35070140cbd6d4acdf7f8bc37f72d0445 (patch)
tree4f9641dbe16fbb6c79010593bf6503bbc0e46a7a /clang/lib/AST/ExprConstant.cpp
parent39bc0529b018a89b4b6a21aaabe240cd3a65c44d (diff)
downloadllvm-f72e53f35070140cbd6d4acdf7f8bc37f72d0445.zip
llvm-f72e53f35070140cbd6d4acdf7f8bc37f72d0445.tar.gz
llvm-f72e53f35070140cbd6d4acdf7f8bc37f72d0445.tar.bz2
[clang][CompundLiteralExpr] Don't defer evaluation for CLEs (#137163)
Previously we would defer evaluation of CLEs until LValue to RValue conversions, which would result in creating values within wrong scope and triggering use-after-frees. This patch instead eagerly evaluates CLEs, within the scope requiring them. This requires storing an extra pointer for CLE expressions with static storage. Fixes https://github.com/llvm/llvm-project/issues/137165
Diffstat (limited to 'clang/lib/AST/ExprConstant.cpp')
-rw-r--r--clang/lib/AST/ExprConstant.cpp90
1 files changed, 49 insertions, 41 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 81c778e..60c658a 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -48,6 +48,7 @@
#include "clang/AST/OptionalDiagnostic.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/DiagnosticSema.h"
@@ -4534,6 +4535,30 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
BaseVal = MTE->getOrCreateValue(false);
assert(BaseVal && "got reference to unevaluated temporary");
+ } else if (const CompoundLiteralExpr *CLE =
+ dyn_cast_or_null<CompoundLiteralExpr>(Base)) {
+ // According to GCC info page:
+ //
+ // 6.28 Compound Literals
+ //
+ // As an optimization, G++ sometimes gives array compound literals
+ // longer lifetimes: when the array either appears outside a function or
+ // has a const-qualified type. If foo and its initializer had elements
+ // of type char *const rather than char *, or if foo were a global
+ // variable, the array would have static storage duration. But it is
+ // probably safest just to avoid the use of array compound literals in
+ // C++ code.
+ //
+ // Obey that rule by checking constness for converted array types.
+ if (QualType CLETy = CLE->getType(); CLETy->isArrayType() &&
+ !LValType->isArrayType() &&
+ !CLETy.isConstant(Info.Ctx)) {
+ Info.FFDiag(E);
+ Info.Note(CLE->getExprLoc(), diag::note_declared_at);
+ return CompleteObject();
+ }
+
+ BaseVal = &CLE->getStaticValue();
} else {
if (!IsAccess)
return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
@@ -4599,44 +4624,7 @@ handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, QualType Type,
WantObjectRepresentation ? AK_ReadObjectRepresentation : AK_Read;
if (Base && !LVal.getLValueCallIndex() && !Type.isVolatileQualified()) {
- if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) {
- // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the
- // initializer until now for such expressions. Such an expression can't be
- // an ICE in C, so this only matters for fold.
- if (Type.isVolatileQualified()) {
- Info.FFDiag(Conv);
- return false;
- }
-
- APValue Lit;
- if (!Evaluate(Lit, Info, CLE->getInitializer()))
- return false;
-
- // According to GCC info page:
- //
- // 6.28 Compound Literals
- //
- // As an optimization, G++ sometimes gives array compound literals longer
- // lifetimes: when the array either appears outside a function or has a
- // const-qualified type. If foo and its initializer had elements of type
- // char *const rather than char *, or if foo were a global variable, the
- // array would have static storage duration. But it is probably safest
- // just to avoid the use of array compound literals in C++ code.
- //
- // Obey that rule by checking constness for converted array types.
-
- QualType CLETy = CLE->getType();
- if (CLETy->isArrayType() && !Type->isArrayType()) {
- if (!CLETy.isConstant(Info.Ctx)) {
- Info.FFDiag(Conv);
- Info.Note(CLE->getExprLoc(), diag::note_declared_at);
- return false;
- }
- }
-
- CompleteObject LitObj(LVal.Base, &Lit, Base->getType());
- return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal, AK);
- } else if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) {
+ if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) {
// Special-case character extraction so we don't have to construct an
// APValue for the whole string.
assert(LVal.Designator.Entries.size() <= 1 &&
@@ -9144,9 +9132,29 @@ bool
LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
assert((!Info.getLangOpts().CPlusPlus || E->isFileScope()) &&
"lvalue compound literal in c++?");
- // Defer visiting the literal until the lvalue-to-rvalue conversion. We can
- // only see this when folding in C, so there's no standard to follow here.
- return Success(E);
+ APValue *Lit;
+ // If CompountLiteral has static storage, its value can be used outside
+ // this expression. So evaluate it once and store it in ASTContext.
+ if (E->hasStaticStorage()) {
+ Lit = &E->getOrCreateStaticValue(Info.Ctx);
+ Result.set(E);
+ // Reset any previously evaluated state, otherwise evaluation below might
+ // fail.
+ // FIXME: Should we just re-use the previously evaluated value instead?
+ *Lit = APValue();
+ } else {
+ assert(!Info.getLangOpts().CPlusPlus);
+ Lit = &Info.CurrentCall->createTemporary(E, E->getInitializer()->getType(),
+ ScopeKind::Block, Result);
+ }
+ // FIXME: Evaluating in place isn't always right. We should figure out how to
+ // use appropriate evaluation context here, see
+ // clang/test/AST/static-compound-literals-reeval.cpp for a failure.
+ if (!EvaluateInPlace(*Lit, Info, Result, E->getInitializer())) {
+ *Lit = APValue();
+ return false;
+ }
+ return true;
}
bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {