Skip to content

Commit 2e5d810

Browse files
committed
Return a proper character array for 'define_static_string'.
This is somewhat tricky, since the character array needs to be associated to a declaration (i.e., a hidden variable), but the declaration won't be parsed and therefore won't get handed off to CodeGen. So unless we do something to tell CodeGen about the variable, it won't get emitted and we'll get linker errors. So we (for now, anyway) introduce a similar mechanism to what's already used for "#pragma weak"; we track any generated decl's in an array held by 'Sema', and pass those explicitly to CodeGen after parsing the AST. We also cache any such generated variables in the ASTContext, partly as an optimization, but mostly to ensure that each such variable obtains a (TU-)unique name. Closes issue llvm#80.
1 parent 774b841 commit 2e5d810

File tree

5 files changed

+77
-10
lines changed

5 files changed

+77
-10
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
324324
/// This is lazily created. This is intentionally not serialized.
325325
mutable llvm::StringMap<StringLiteral *> StringLiteralCache;
326326

327+
/// A cache mapping a string value to a VarDecl object holding a generated
328+
/// immutable character array containing the same string.
329+
///
330+
/// This is lazily created. This is intentionally not serialized.
331+
mutable llvm::StringMap<VarDecl *> GenCharArrayCache;
332+
mutable llvm::StringMap<VarDecl *> GenUTF8CharArrayCache;
333+
327334
/// MD5 hash of CUID. It is calculated when first used and cached by this
328335
/// data member.
329336
mutable std::string CUIDHash;
@@ -3247,6 +3254,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
32473254
/// PredefinedExpr to cache evaluated results.
32483255
StringLiteral *getPredefinedStringLiteralFromCache(StringRef Key) const;
32493256

3257+
/// Return a variable whose holding a generated immutable character array
3258+
/// containing the same string.
3259+
VarDecl *getGeneratedCharArray(StringRef Key, bool IsUtf8);
3260+
32503261
/// Return a declaration for the global GUID object representing the given
32513262
/// GUID value.
32523263
MSGuidDecl *getMSGuidDecl(MSGuidDeclParts Parts) const;

clang/include/clang/Sema/Sema.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15287,6 +15287,17 @@ class Sema final : public SemaBase {
1528715287

1528815288
QualType ComputeResultType(QualType ExprTy, const APValue &V);
1528915289

15290+
/// GeneratedDecl - Translation-unit scoped declarations generated by
15291+
/// reflection metafunctions (C++2c P2996).
15292+
///
15293+
/// Since these declarations are formed as side-effects of constant
15294+
/// evaluation, the parser will not "see" them and will not pass them to
15295+
/// the CodeGenModule. Maintaining a separate list addresses the problem.
15296+
SmallVector<Decl *, 4> GeneratedDecl;
15297+
15298+
/// GeneratedDecls - access to metafunction generated Decls
15299+
SmallVectorImpl<Decl *> &GeneratedDecls() { return GeneratedDecl; }
15300+
1529015301

1529115302
private:
1529215303
// Lambdas having bound references to this Sema object, used to evaluate

clang/lib/AST/ASTContext.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12895,6 +12895,26 @@ ASTContext::getPredefinedStringLiteralFromCache(StringRef Key) const {
1289512895
return Result;
1289612896
}
1289712897

12898+
VarDecl *
12899+
ASTContext::getGeneratedCharArray(StringRef Key, bool Utf8) {
12900+
auto &Cache = Utf8 ? GenUTF8CharArrayCache : GenCharArrayCache;
12901+
VarDecl *&Result = Cache[Key];
12902+
if (!Result) {
12903+
std::string Name;
12904+
{
12905+
llvm::raw_string_ostream NameOut(Name);
12906+
NameOut << "__gen_char_array_" << Cache.size();
12907+
}
12908+
12909+
QualType CharGenTy = Utf8 ? Char8Ty : CharTy;
12910+
QualType LitTy = getStringLiteralArrayType(CharGenTy, Key.size());
12911+
12912+
Result = VarDecl::Create(*this, TUDecl, SourceLocation(), SourceLocation(),
12913+
&Idents.get(Name), LitTy, nullptr, SC_Static);
12914+
}
12915+
return Result;
12916+
}
12917+
1289812918
MSGuidDecl *
1289912919
ASTContext::getMSGuidDecl(MSGuidDecl::Parts Parts) const {
1290012920
assert(MSGuidTagDecl && "building MS GUID without MS extensions?");

clang/lib/Parse/ParseAST.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
177177
}
178178
}
179179

180+
// Process any TopLevelDecls generated by reflection metafunctions.
181+
for (Decl *D : S.GeneratedDecls())
182+
Consumer->HandleTopLevelDecl(DeclGroupRef(D));
183+
180184
// Process any TopLevelDecls generated by #pragma weak.
181185
for (Decl *D : S.WeakTopLevelDecls())
182186
Consumer->HandleTopLevelDecl(DeclGroupRef(D));

clang/lib/Sema/Metafunctions.cpp

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,8 @@ static APValue makeReflection(TagDataMemberSpec *TDMS) {
644644
return APValue(RV);
645645
}
646646

647-
static Expr *makeCString(StringRef Str, ASTContext &C, bool Utf8) {
647+
static Expr *makeCString(StringRef Str, ASTContext &C, bool Utf8,
648+
bool CastToPtr) {
648649
QualType ConstCharTy = (Utf8 ? C.Char8Ty : C.CharTy).withConst();
649650

650651
// Get the type for 'const char[Str.size()]'.
@@ -655,14 +656,18 @@ static Expr *makeCString(StringRef Str, ASTContext &C, bool Utf8) {
655656
// Create a string literal having type 'const char [Str.size()]'.
656657
StringLiteralKind SLK = Utf8 ? StringLiteralKind::UTF8 :
657658
StringLiteralKind::Ordinary;
658-
StringLiteral *StrLit = StringLiteral::Create(C, Str, SLK, false, StrLitTy,
659-
SourceLocation{});
659+
Expr *Synthesized = StringLiteral::Create(C, Str, SLK, false, StrLitTy,
660+
SourceLocation{});
660661

661-
// Create an expression to implicitly cast the literal to 'const char *'.
662-
QualType ConstCharPtrTy = C.getPointerType(ConstCharTy);
663-
return ImplicitCastExpr::Create(C, ConstCharPtrTy, CK_ArrayToPointerDecay,
664-
StrLit, /*BasePath=*/nullptr, VK_PRValue,
665-
FPOptionsOverride());
662+
if (CastToPtr) {
663+
// Create an expression to implicitly cast the literal to 'const char *'.
664+
QualType ConstCharPtrTy = C.getPointerType(ConstCharTy);
665+
Synthesized = ImplicitCastExpr::Create(C, ConstCharPtrTy,
666+
CK_ArrayToPointerDecay, Synthesized,
667+
/*BasePath=*/nullptr, VK_PRValue,
668+
FPOptionsOverride());
669+
}
670+
return Synthesized;
666671
}
667672

668673
static bool SetAndSucceed(APValue &Out, const APValue &Result) {
@@ -1823,7 +1828,9 @@ bool identifier_of(APValue &Result, Sema &S, EvalFn Evaluator, DiagFn Diagnoser,
18231828
return Diagnoser(Range.getBegin(), diag::metafn_anonymous_entity)
18241829
<< DescriptionOf(R.getReflection()) << Range;
18251830

1826-
return !Evaluator(Result, makeCString(Name, S.Context, IsUtf8), true);
1831+
return !Evaluator(Result,
1832+
makeCString(Name, S.Context, IsUtf8, /*CastToPtr=*/true),
1833+
true);
18271834
}
18281835

18291836
bool has_identifier(APValue &Result, Sema &S, EvalFn Evaluator,
@@ -5286,7 +5293,21 @@ bool define_static_string(APValue &Result, Sema &S, EvalFn Evaluator,
52865293
return true;
52875294
bool IsUtf8 = Scratch.getInt().getBoolValue();
52885295

5289-
return !Evaluator(Result, makeCString(Contents, S.Context, IsUtf8), true);
5296+
VarDecl *AnonArr = S.Context.getGeneratedCharArray(Contents, IsUtf8);
5297+
if (!AnonArr->hasInit()) {
5298+
Expr *StrLit = makeCString(Contents, S.Context, IsUtf8,
5299+
/*CastToPtr=*/false);
5300+
5301+
AnonArr->setConstexpr(true);
5302+
S.AddInitializerToDecl(AnonArr, StrLit, false);
5303+
5304+
S.GeneratedDecl.push_back(AnonArr);
5305+
}
5306+
assert(AnonArr->getFormalLinkage() == Linkage::Internal);
5307+
5308+
APValue::LValuePathEntry Path[1] = {APValue::LValuePathEntry::ArrayIndex(0)};
5309+
return SetAndSucceed(Result,
5310+
APValue(AnonArr, CharUnits::Zero(), Path, false));
52905311
}
52915312

52925313
bool get_ith_parameter_of(APValue &Result, Sema &S, EvalFn Evaluator,

0 commit comments

Comments
 (0)