https://github.com/awson created https://github.com/llvm/llvm-project/pull/172995
This is a rework of https://github.com/llvm/llvm-project/pull/156846. We now only clone (parenthesized) string literals only when doing `TreeTransform::TransformExpr`. Non-dependent case remains unaffected thus. >From 3441e676e8556d0fa29748cb4895444fb079b015 Mon Sep 17 00:00:00 2001 From: awson <[email protected]> Date: Fri, 19 Dec 2025 07:43:21 +0300 Subject: [PATCH] If we ever want to transform (possibly parenthesized) `StringLiteral` expression then clone it beforehand. (add string literal cloner to `Expr` class for this) --- clang/include/clang/AST/Expr.h | 4 ++ clang/lib/AST/Expr.cpp | 79 +++++++++++++++++++++++++++++++++ clang/lib/Sema/TreeTransform.h | 1 + clang/test/SemaCXX/GH112189.cpp | 41 +++++++++++++++++ 4 files changed, 125 insertions(+) create mode 100644 clang/test/SemaCXX/GH112189.cpp diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 3e30a8b420f19..4e219d50111fe 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -1023,6 +1023,10 @@ class Expr : public ValueStmt { return skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); } + /// If the expression is a (possibly parenthesized) string literal + /// then make a copy of it. + Expr *CloneIfIAmAStringLiteral(ASTContext &Ctx); + /// Checks that the two Expr's will refer to the same value as a comparison /// operand. The caller must ensure that the values referenced by the Expr's /// are not modified between E1 and E2 or the result my be invalid. diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 616db5df23c5f..ed7cfa8de83b4 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -133,6 +133,85 @@ const Expr *Expr::skipRValueSubobjectAdjustments( return E; } +static StringLiteral *CloneStringLiteral(const StringLiteral *SL, + ASTContext &C) { + SourceLocation *SLocs = new (C) SourceLocation[SL->getNumConcatenated()]; + std::copy(SL->tokloc_begin(), SL->tokloc_end(), SLocs); + return StringLiteral::Create( + C, SL->getBytes(), SL->getKind(), SL->isPascal(), SL->getType(), + ArrayRef<SourceLocation>(SLocs, SL->getNumConcatenated())); +} + +// Exactly follow `IgnoreParensSingleStep` (`AST/IgnoreExpr.h`) +// We only recursively visit those subexpressions which `IgnoreParensSingleStep` +// drills down to. +Expr *Expr::CloneIfIAmAStringLiteral(ASTContext &C){ + if (auto *SL = dyn_cast<StringLiteral>(this)) { + return CloneStringLiteral(SL, C); + } + + if (auto *PE = dyn_cast<ParenExpr>(this)) { + return new (C) + ParenExpr(PE->getBeginLoc(), PE->getEndLoc(), + PE->getSubExpr()->CloneIfIAmAStringLiteral(C)); + } + + if (auto *UO = dyn_cast<UnaryOperator>(this)) { + if (UO->getOpcode() == UO_Extension) { + return UnaryOperator::Create( + C, UO->getSubExpr()->CloneIfIAmAStringLiteral(C), UO_Extension, + UO->getType(), UO->getValueKind(), UO->getObjectKind(), + UO->getBeginLoc(), UO->canOverflow(), UO->getFPOptionsOverride()); + } + } + + else if (auto *GSE = dyn_cast<GenericSelectionExpr>(this)) { + if (!GSE->isResultDependent()) { + ArrayRef<Expr *> GSEAEs = GSE->getAssocExprs(); + Expr **NewGSEAEs = new (C) Expr *[GSEAEs.size()]; + std::copy(GSEAEs.begin(), GSEAEs.end(), NewGSEAEs); + NewGSEAEs[GSE->getResultIndex()] = + GSE->getResultExpr()->CloneIfIAmAStringLiteral(C); + + auto GSECreate = [&](auto *ExprOrTSI) -> Expr * { + return GenericSelectionExpr::Create( + C, GSE->getGenericLoc(), ExprOrTSI, GSE->getAssocTypeSourceInfos(), + ArrayRef<Expr *>(NewGSEAEs, GSEAEs.size()), GSE->getDefaultLoc(), + GSE->getRParenLoc(), GSE->containsUnexpandedParameterPack(), + GSE->getResultIndex()); + }; + + return GSE->isExprPredicate() ? GSECreate(GSE->getControllingExpr()) + : GSECreate(GSE->getControllingType()); + } + } + + else if (auto *CE = dyn_cast<ChooseExpr>(this)) { + if (!CE->isConditionDependent()) { + // Drills to `CE->getChosenSubExpr()` + const bool isCondTrue = CE->isConditionTrue(); + return new (C) ChooseExpr( + CE->getBeginLoc(), CE->getCond(), + isCondTrue ? CE->getLHS()->CloneIfIAmAStringLiteral(C) + : CE->getLHS(), + isCondTrue ? CE->getRHS() + : CE->getRHS()->CloneIfIAmAStringLiteral(C), + CE->getType(), CE->getValueKind(), CE->getObjectKind(), + CE->getRParenLoc(), CE->isConditionTrue()); + } + } + + else if (auto *PE = dyn_cast<PredefinedExpr>(this)) { + if (PE->isTransparent() && PE->getFunctionName()) { + return PredefinedExpr::Create( + C, PE->getLocation(), PE->getType(), PE->getIdentKind(), + PE->isTransparent(), CloneStringLiteral(PE->getFunctionName(), C)); + } + } + + return this; +} + bool Expr::isKnownToHaveBooleanValue(bool Semantic) const { const Expr *E = IgnoreParens(); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index bc923c80b7132..81048c9fe1640 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -4417,6 +4417,7 @@ ExprResult TreeTransform<Derived>::TransformExpr(Expr *E) { if (!E) return E; + E = E->CloneIfIAmAStringLiteral(getSema().getASTContext()); switch (E->getStmtClass()) { case Stmt::NoStmtClass: break; #define STMT(Node, Parent) case Stmt::Node##Class: break; diff --git a/clang/test/SemaCXX/GH112189.cpp b/clang/test/SemaCXX/GH112189.cpp new file mode 100644 index 0000000000000..036fd8ea83c0e --- /dev/null +++ b/clang/test/SemaCXX/GH112189.cpp @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -verify %s +// expected-no-diagnostics + +template<unsigned int SPACE> +char foo_choose() { + char buffer[SPACE] {__builtin_choose_expr(6, "foo", "boo")}; + return buffer[0]; +} + +int boro_choose() +{ + int r = foo_choose<10>(); + r += foo_choose<100>(); + return r + foo_choose<4>(); +} + +template<unsigned int SPACE> +char foo_gen_ext() { + char buffer[SPACE] {__extension__ (_Generic(0, int: (__extension__ "foo" )))}; + return buffer[0]; +} + +int boro_gen_ext() +{ + int r = foo_gen_ext<10>(); + r += foo_gen_ext<100>(); + return r + foo_gen_ext<4>(); +} + +template<unsigned int SPACE> +char foo_paren_predef() { + char buffer[SPACE] {(((__FILE__)))}; + return buffer[0]; +} + +int boro_paren_predef() +{ + int r = foo_paren_predef<200000>(); + r += foo_paren_predef<300000>(); + return r + foo_paren_predef<100000>(); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
