Skip to content

Commit 14864e6

Browse files
committed
updateStringLiteralType recursively clones subexpressions which types it modifies.
Done as a separate static function and not inlined directly into the `updateStringLiteralType` function for maintainability.
1 parent 7fb1dc0 commit 14864e6

File tree

2 files changed

+147
-19
lines changed

2 files changed

+147
-19
lines changed

clang/lib/Sema/SemaInit.cpp

Lines changed: 106 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -168,16 +168,99 @@ bool Sema::IsStringInit(Expr *Init, const ArrayType *AT) {
168168
return ::IsStringInit(Init, AT, Context) == SIF_None;
169169
}
170170

171+
static StringLiteral *CloneStringLiteral(const StringLiteral *SL,
172+
ASTContext &C) {
173+
SourceLocation *SLocs = new (C) SourceLocation[SL->getNumConcatenated()];
174+
std::copy(SL->tokloc_begin(), SL->tokloc_end(), SLocs);
175+
return StringLiteral::Create(
176+
C, SL->getBytes(), SL->getKind(), SL->isPascal(), SL->getType(),
177+
ArrayRef<SourceLocation>(SLocs, SL->getNumConcatenated()));
178+
}
179+
180+
// Exactly follow `IgnoreParensSingleStep` (`AST/IgnoreExpr.h`)
181+
// We only recursively visit those subexpressions which `IgnoreParensSingleStep`
182+
// drills down to.
183+
static Expr *CloneWithRecurseToInnermostSL(Expr *E, ASTContext &C) {
184+
if (auto *SL = dyn_cast<StringLiteral>(E)) {
185+
return CloneStringLiteral(SL, C);
186+
}
187+
188+
if (auto *PE = dyn_cast<ParenExpr>(E)) {
189+
return new (C)
190+
ParenExpr(PE->getBeginLoc(), PE->getEndLoc(),
191+
CloneWithRecurseToInnermostSL(PE->getSubExpr(), C));
192+
}
193+
194+
if (auto *UO = dyn_cast<UnaryOperator>(E)) {
195+
if (UO->getOpcode() == UO_Extension) {
196+
return UnaryOperator::Create(
197+
C, CloneWithRecurseToInnermostSL(UO->getSubExpr(), C), UO_Extension,
198+
UO->getType(), UO->getValueKind(), UO->getObjectKind(),
199+
UO->getBeginLoc(), UO->canOverflow(), UO->getFPOptionsOverride());
200+
}
201+
}
202+
203+
else if (auto *GSE = dyn_cast<GenericSelectionExpr>(E)) {
204+
if (!GSE->isResultDependent()) {
205+
ArrayRef<Expr *> GSEAEs = GSE->getAssocExprs();
206+
Expr **NewGSEAEs = new (C) Expr *[GSEAEs.size()];
207+
std::copy(GSEAEs.begin(), GSEAEs.end(), NewGSEAEs);
208+
NewGSEAEs[GSE->getResultIndex()] =
209+
CloneWithRecurseToInnermostSL(GSE->getResultExpr(), C);
210+
211+
auto GSECreate = [&](auto *ExprOrTSI) -> Expr * {
212+
return GenericSelectionExpr::Create(
213+
C, GSE->getGenericLoc(), ExprOrTSI, GSE->getAssocTypeSourceInfos(),
214+
ArrayRef<Expr *>(NewGSEAEs, GSEAEs.size()), GSE->getDefaultLoc(),
215+
GSE->getRParenLoc(), GSE->containsUnexpandedParameterPack(),
216+
GSE->getResultIndex());
217+
};
218+
219+
return GSE->isExprPredicate() ? GSECreate(GSE->getControllingExpr())
220+
: GSECreate(GSE->getControllingType());
221+
}
222+
}
223+
224+
else if (auto *CE = dyn_cast<ChooseExpr>(E)) {
225+
if (!CE->isConditionDependent()) {
226+
// Drills to `CE->getChosenSubExpr()`
227+
const bool isCondTrue = CE->isConditionTrue();
228+
return new (C) ChooseExpr(
229+
CE->getBeginLoc(), CE->getCond(),
230+
isCondTrue ? CloneWithRecurseToInnermostSL(CE->getLHS(), C)
231+
: CE->getLHS(),
232+
isCondTrue ? CE->getRHS()
233+
: CloneWithRecurseToInnermostSL(CE->getRHS(), C),
234+
CE->getType(), CE->getValueKind(), CE->getObjectKind(),
235+
CE->getRParenLoc(), CE->isConditionTrue());
236+
}
237+
}
238+
239+
else if (auto *PE = dyn_cast<PredefinedExpr>(E)) {
240+
if (PE->isTransparent() && PE->getFunctionName()) {
241+
return PredefinedExpr::Create(
242+
C, PE->getLocation(), PE->getType(), PE->getIdentKind(),
243+
PE->isTransparent(), CloneStringLiteral(PE->getFunctionName(), C));
244+
}
245+
}
246+
247+
return E;
248+
}
249+
171250
/// Update the type of a string literal, including any surrounding parentheses,
172251
/// to match the type of the object which it is initializing.
173-
static void updateStringLiteralType(Expr *E, QualType Ty) {
252+
static Expr *updateStringLiteralType(Expr *E, QualType Ty, Sema &S) {
253+
Expr *ENew = CloneWithRecurseToInnermostSL(E, S.Context);
254+
E = ENew;
255+
174256
while (true) {
175257
E->setType(Ty);
176258
E->setValueKind(VK_PRValue);
177259
if (isa<StringLiteral>(E) || isa<ObjCEncodeExpr>(E))
178260
break;
179261
E = IgnoreParensSingleStep(E);
180262
}
263+
return ENew;
181264
}
182265

183266
/// Fix a compound literal initializing an array so it's correctly marked
@@ -209,9 +292,9 @@ static bool initializingConstexprVariable(const InitializedEntity &Entity) {
209292
static void CheckC23ConstexprInitStringLiteral(const StringLiteral *SE,
210293
Sema &SemaRef, QualType &TT);
211294

212-
static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
213-
Sema &S, const InitializedEntity &Entity,
214-
bool CheckC23ConstexprInit = false) {
295+
static Expr *CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
296+
Sema &S, const InitializedEntity &Entity,
297+
bool CheckC23ConstexprInit = false) {
215298
// Get the length of the string as parsed.
216299
auto *ConstantArrayTy =
217300
cast<ConstantArrayType>(Str->getType()->getAsArrayTypeUnsafe());
@@ -228,8 +311,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
228311
// Return a new array type (C99 6.7.8p22).
229312
DeclT = S.Context.getConstantArrayType(
230313
IAT->getElementType(), ConstVal, nullptr, ArraySizeModifier::Normal, 0);
231-
updateStringLiteralType(Str, DeclT);
232-
return;
314+
return updateStringLiteralType(Str, DeclT, S);
233315
}
234316

235317
const ConstantArrayType *CAT = cast<ConstantArrayType>(AT);
@@ -302,7 +384,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
302384
// something like:
303385
// char x[1] = "foo";
304386
// then this will set the string literal's type to char[1].
305-
updateStringLiteralType(Str, DeclT);
387+
return updateStringLiteralType(Str, DeclT, S);
306388
}
307389

308390
void emitUninitializedExplicitInitFields(Sema &S, const RecordDecl *R) {
@@ -1608,10 +1690,12 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
16081690

16091691
if (IsStringInit(expr, arrayType, SemaRef.Context) == SIF_None) {
16101692
// FIXME: Should we do this checking in verify-only mode?
1611-
if (!VerifyOnly)
1612-
CheckStringInit(expr, ElemType, arrayType, SemaRef, Entity,
1613-
SemaRef.getLangOpts().C23 &&
1614-
initializingConstexprVariable(Entity));
1693+
if (!VerifyOnly) {
1694+
expr = CheckStringInit(expr, ElemType, arrayType, SemaRef, Entity,
1695+
SemaRef.getLangOpts().C23 &&
1696+
initializingConstexprVariable(Entity));
1697+
IList->setInit(Index, expr);
1698+
}
16151699
if (StructuredList)
16161700
UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
16171701
++Index;
@@ -2121,10 +2205,13 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
21212205
// because doing so would involve allocating one character
21222206
// constant for each string.
21232207
// FIXME: Should we do these checks in verify-only mode too?
2124-
if (!VerifyOnly)
2125-
CheckStringInit(
2126-
IList->getInit(Index), DeclType, arrayType, SemaRef, Entity,
2127-
SemaRef.getLangOpts().C23 && initializingConstexprVariable(Entity));
2208+
if (!VerifyOnly) {
2209+
IList->setInit(
2210+
Index, CheckStringInit(IList->getInit(Index), DeclType, arrayType,
2211+
SemaRef, Entity,
2212+
SemaRef.getLangOpts().C23 &&
2213+
initializingConstexprVariable(Entity)));
2214+
}
21282215
if (StructuredList) {
21292216
UpdateStructuredListElement(StructuredList, StructuredIndex,
21302217
IList->getInit(Index));
@@ -8421,10 +8508,10 @@ ExprResult InitializationSequence::Perform(Sema &S,
84218508
case SK_StringInit: {
84228509
QualType Ty = Step->Type;
84238510
bool UpdateType = ResultType && Entity.getType()->isIncompleteArrayType();
8424-
CheckStringInit(CurInit.get(), UpdateType ? *ResultType : Ty,
8425-
S.Context.getAsArrayType(Ty), S, Entity,
8426-
S.getLangOpts().C23 &&
8427-
initializingConstexprVariable(Entity));
8511+
CurInit = CheckStringInit(CurInit.get(), UpdateType ? *ResultType : Ty,
8512+
S.Context.getAsArrayType(Ty), S, Entity,
8513+
S.getLangOpts().C23 &&
8514+
initializingConstexprVariable(Entity));
84288515
break;
84298516
}
84308517

clang/test/SemaCXX/GH112189.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %clang_cc1 -verify %s
2+
// expected-no-diagnostics
3+
4+
template<unsigned int SPACE>
5+
char foo_choose() {
6+
char buffer[SPACE] {__builtin_choose_expr(6, "foo", "boo")};
7+
return buffer[0];
8+
}
9+
10+
int boro_choose()
11+
{
12+
int r = foo_choose<10>();
13+
r += foo_choose<100>();
14+
return r + foo_choose<4>();
15+
}
16+
17+
template<unsigned int SPACE>
18+
char foo_gen_ext() {
19+
char buffer[SPACE] {__extension__ (_Generic(0, int: (__extension__ "foo" )))};
20+
return buffer[0];
21+
}
22+
23+
int boro_gen_ext()
24+
{
25+
int r = foo_gen_ext<10>();
26+
r += foo_gen_ext<100>();
27+
return r + foo_gen_ext<4>();
28+
}
29+
30+
template<unsigned int SPACE>
31+
char foo_paren_predef() {
32+
char buffer[SPACE] {(((__FILE__)))};
33+
return buffer[0];
34+
}
35+
36+
int boro_paren_predef()
37+
{
38+
int r = foo_paren_predef<200000>();
39+
r += foo_paren_predef<300000>();
40+
return r + foo_paren_predef<100000>();
41+
}

0 commit comments

Comments
 (0)