Skip to content

Commit 44d6030

Browse files
Erich Keanebader
Erich Keane
authored andcommitted
First attempt at __unique_stable_name
This implementation uses the keyword __unique_stable_name as an operator that can take a type or expression, and will result in a constexpr constant character array that (hopefully) uniquely represents the type or type-of-expression being passed to it. The unique representation is the normal mangled name of the type, except in the cases of a lambda, where the ordinal "number" is just replaced with LINE->COL. Macro expansions are also appended with '~' followed by the LINE->COL that it appears in. For example, a lambda declared in 'main' would look like _ZTSZ4mainEUlvE25->12 (line 25, column 12). A Lambda that comes from a macro looks like: _ZTSZ4mainEUlvE45->3~18->32 (macro invoked on 45/3, lambda defined inside the macro on line 18, column 32). Template instantiations based on the lambda would result in a name that contains the lambda mangling, for example: _ZTSZ3bazIZ4mainEUlvE25->12EvvEUlvE14->12 A function template named 'baz' that is instantiated with a lambda declared in 'main' on line 25/col 12 has another macro in it, declared on line 14, column 12. Signed-off-by: Erich Keane <[email protected]>
1 parent 272ca00 commit 44d6030

File tree

13 files changed

+454
-17
lines changed

13 files changed

+454
-17
lines changed

clang/docs/LanguageExtensions.rst

+24
Original file line numberDiff line numberDiff line change
@@ -1950,6 +1950,30 @@ form of ``__builtin_operator_delete`` is currently available.
19501950
These builtins are intended for use in the implementation of ``std::allocator``
19511951
and other similar allocation libraries, and are only available in C++.
19521952
1953+
``__unique_stable_name``
1954+
------------------------
1955+
1956+
``__unique_stable_name()`` is a builtin that takes a type or expression and
1957+
produces a string literal containing a unique name for the type (or type of the
1958+
expression) that is stable across split compilations.
1959+
1960+
In cases where the split compilation needs to share a unique token for a type
1961+
across the boundary (such as in an offloading situation), this name can be used
1962+
for lookup purposes.
1963+
1964+
This builtin is superior to RTTI for this purpose for two reasons. First, this
1965+
value is computed entirely at compile time, so it can be used in constant
1966+
expressions. Second, this value encodes lambda functions based on line-number
1967+
rather than the order in which it appears in a function. This is valuable
1968+
because it is stable in cases where an unrelated lambda is introduced
1969+
conditionally in the same function.
1970+
1971+
The current implementation of this builtin uses a slightly modified Itanium
1972+
Mangler to produce the unique name. The lambda ordinal is replaced with one or
1973+
more line/column pairs in the format ``LINE->COL``, separated with a ``~``
1974+
character. Typically, only one pair will be included, however in the case of
1975+
macro expansions, the entire macro expansion stack is expressed.
1976+
19531977
Multiprecision Arithmetic Builtins
19541978
----------------------------------
19551979

clang/include/clang/AST/Expr.h

+74-13
Original file line numberDiff line numberDiff line change
@@ -1787,10 +1787,16 @@ class StringLiteral final
17871787
}
17881788
};
17891789

1790+
union PredefExprStorage {
1791+
Stmt *S;
1792+
Expr *E;
1793+
TypeSourceInfo *T;
1794+
};
1795+
17901796
/// [C99 6.4.2.2] - A predefined identifier such as __func__.
17911797
class PredefinedExpr final
17921798
: public Expr,
1793-
private llvm::TrailingObjects<PredefinedExpr, Stmt *> {
1799+
private llvm::TrailingObjects<PredefinedExpr, PredefExprStorage> {
17941800
friend class ASTStmtReader;
17951801
friend TrailingObjects;
17961802

@@ -1809,12 +1815,18 @@ class PredefinedExpr final
18091815
PrettyFunction,
18101816
/// The same as PrettyFunction, except that the
18111817
/// 'virtual' keyword is omitted for virtual member functions.
1812-
PrettyFunctionNoVirtual
1818+
PrettyFunctionNoVirtual,
1819+
UniqueStableNameType,
1820+
UniqueStableNameExpr,
18131821
};
18141822

18151823
private:
18161824
PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
18171825
StringLiteral *SL);
1826+
PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
1827+
TypeSourceInfo *Info);
1828+
PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
1829+
Expr *E);
18181830

18191831
explicit PredefinedExpr(EmptyShell Empty, bool HasFunctionName);
18201832

@@ -1824,14 +1836,34 @@ class PredefinedExpr final
18241836
void setFunctionName(StringLiteral *SL) {
18251837
assert(hasFunctionName() &&
18261838
"This PredefinedExpr has no storage for a function name!");
1827-
*getTrailingObjects<Stmt *>() = SL;
1839+
getTrailingObjects<PredefExprStorage>()->S = SL;
1840+
}
1841+
1842+
void setTypeSourceInfo(TypeSourceInfo *Info) {
1843+
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameType &&
1844+
"TypeSourceInfo only valid for UniqueStableName of a Type");
1845+
getTrailingObjects<PredefExprStorage>()->T = Info;
1846+
}
1847+
1848+
void setExpr(Expr *E) {
1849+
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr &&
1850+
"Expr only valid for UniqueStableName of an Expression.");
1851+
getTrailingObjects<PredefExprStorage>()->E = E;
18281852
}
18291853

18301854
public:
18311855
/// Create a PredefinedExpr.
18321856
static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L,
18331857
QualType FNTy, IdentKind IK, StringLiteral *SL);
18341858

1859+
static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L,
1860+
QualType FnTy, IdentKind IK, StringLiteral *SL,
1861+
TypeSourceInfo *Info);
1862+
1863+
static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L,
1864+
QualType FnTy, IdentKind IK, StringLiteral *SL,
1865+
Expr *E);
1866+
18351867
/// Create an empty PredefinedExpr.
18361868
static PredefinedExpr *CreateEmpty(const ASTContext &Ctx,
18371869
bool HasFunctionName);
@@ -1843,20 +1875,47 @@ class PredefinedExpr final
18431875
SourceLocation getLocation() const { return PredefinedExprBits.Loc; }
18441876
void setLocation(SourceLocation L) { PredefinedExprBits.Loc = L; }
18451877

1878+
TypeSourceInfo *getTypeSourceInfo() {
1879+
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameType &&
1880+
"TypeSourceInfo only valid for UniqueStableName of a Type");
1881+
return getTrailingObjects<PredefExprStorage>()->T;
1882+
}
1883+
1884+
const TypeSourceInfo *getTypeSourceInfo() const {
1885+
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameType &&
1886+
"TypeSourceInfo only valid for UniqueStableName of a Type");
1887+
return getTrailingObjects<PredefExprStorage>()->T;
1888+
}
1889+
1890+
Expr *getExpr() {
1891+
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr &&
1892+
"Expr only valid for UniqueStableName of an Expression.");
1893+
return getTrailingObjects<PredefExprStorage>()->E;
1894+
}
1895+
1896+
const Expr *getExpr() const {
1897+
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr &&
1898+
"Expr only valid for UniqueStableName of an Expression.");
1899+
return getTrailingObjects<PredefExprStorage>()->E;
1900+
}
1901+
1902+
18461903
StringLiteral *getFunctionName() {
1847-
return hasFunctionName()
1848-
? static_cast<StringLiteral *>(*getTrailingObjects<Stmt *>())
1849-
: nullptr;
1904+
return hasFunctionName() ? static_cast<StringLiteral *>(
1905+
getTrailingObjects<PredefExprStorage>()->S)
1906+
: nullptr;
18501907
}
18511908

18521909
const StringLiteral *getFunctionName() const {
1853-
return hasFunctionName()
1854-
? static_cast<StringLiteral *>(*getTrailingObjects<Stmt *>())
1855-
: nullptr;
1910+
return hasFunctionName() ? static_cast<StringLiteral *>(
1911+
getTrailingObjects<PredefExprStorage>()->S)
1912+
: nullptr;
18561913
}
18571914

18581915
static StringRef getIdentKindName(IdentKind IK);
18591916
static std::string ComputeName(IdentKind IK, const Decl *CurrentDecl);
1917+
static std::string ComputeName(ASTContext &Ctx, IdentKind IK,
1918+
const QualType Ty);
18601919

18611920
SourceLocation getBeginLoc() const { return getLocation(); }
18621921
SourceLocation getEndLoc() const { return getLocation(); }
@@ -1867,13 +1926,15 @@ class PredefinedExpr final
18671926

18681927
// Iterators
18691928
child_range children() {
1870-
return child_range(getTrailingObjects<Stmt *>(),
1871-
getTrailingObjects<Stmt *>() + hasFunctionName());
1929+
return child_range(&getTrailingObjects<PredefExprStorage>()->S,
1930+
&getTrailingObjects<PredefExprStorage>()->S +
1931+
hasFunctionName());
18721932
}
18731933

18741934
const_child_range children() const {
1875-
return const_child_range(getTrailingObjects<Stmt *>(),
1876-
getTrailingObjects<Stmt *>() + hasFunctionName());
1935+
return const_child_range(&getTrailingObjects<PredefExprStorage>()->S,
1936+
&getTrailingObjects<PredefExprStorage>()->S +
1937+
hasFunctionName());
18771938
}
18781939
};
18791940

clang/include/clang/AST/Mangle.h

+10
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,14 @@ class MangleContext {
151151
};
152152

153153
class ItaniumMangleContext : public MangleContext {
154+
bool IsUniqueNameMangler = false;
154155
public:
155156
explicit ItaniumMangleContext(ASTContext &C, DiagnosticsEngine &D)
156157
: MangleContext(C, D, MK_Itanium) {}
158+
explicit ItaniumMangleContext(ASTContext &C, DiagnosticsEngine &D,
159+
bool IsUniqueNameMangler)
160+
: MangleContext(C, D, MK_Itanium),
161+
IsUniqueNameMangler(IsUniqueNameMangler) {}
157162

158163
virtual void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) = 0;
159164
virtual void mangleCXXVTT(const CXXRecordDecl *RD, raw_ostream &) = 0;
@@ -170,12 +175,17 @@ class ItaniumMangleContext : public MangleContext {
170175
virtual void mangleCXXDtorComdat(const CXXDestructorDecl *D,
171176
raw_ostream &) = 0;
172177

178+
bool isUniqueNameMangler() { return IsUniqueNameMangler; }
179+
173180
static bool classof(const MangleContext *C) {
174181
return C->getKind() == MK_Itanium;
175182
}
176183

177184
static ItaniumMangleContext *create(ASTContext &Context,
178185
DiagnosticsEngine &Diags);
186+
static ItaniumMangleContext *create(ASTContext &Context,
187+
DiagnosticsEngine &Diags,
188+
bool IsUniqueNameMangler);
179189
};
180190

181191
class MicrosoftMangleContext : public MangleContext {

clang/include/clang/Basic/TokenKinds.def

+1
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,7 @@ ALIAS("__char16_t" , char16_t , KEYCXX)
672672
ALIAS("__char32_t" , char32_t , KEYCXX)
673673

674674
KEYWORD(__builtin_available , KEYALL)
675+
KEYWORD(__unique_stable_name , KEYALL)
675676

676677
// Clang-specific keywords enabled only in testing.
677678
TESTING_KEYWORD(__unknown_anytype , KEYALL)

clang/include/clang/Parse/Parser.h

+1
Original file line numberDiff line numberDiff line change
@@ -1681,6 +1681,7 @@ class Parser : public CodeCompletionHandler {
16811681
ExprResult ParsePostfixExpressionSuffix(ExprResult LHS);
16821682
ExprResult ParseUnaryExprOrTypeTraitExpression();
16831683
ExprResult ParseBuiltinPrimaryExpression();
1684+
ExprResult ParseUniqueStableNameExpression();
16841685

16851686
ExprResult ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
16861687
bool &isCastExpr,

clang/include/clang/Sema/Sema.h

+8
Original file line numberDiff line numberDiff line change
@@ -4467,6 +4467,14 @@ class Sema {
44674467
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
44684468
ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);
44694469

4470+
ExprResult BuildUniqueStableName(SourceLocation OpLoc,
4471+
TypeSourceInfo *Operand);
4472+
ExprResult BuildUniqueStableName(SourceLocation OpLoc, Expr *E);
4473+
ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc, SourceLocation L,
4474+
SourceLocation R, ParsedType Ty);
4475+
ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc, SourceLocation L,
4476+
SourceLocation R, Expr *Operand);
4477+
44704478
bool CheckLoopHintExpr(Expr *E, SourceLocation Loc);
44714479

44724480
ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr);

clang/lib/AST/Expr.cpp

+79-3
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,38 @@ PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
489489
setFunctionName(SL);
490490
}
491491

492+
PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
493+
TypeSourceInfo *Info)
494+
: Expr(PredefinedExprClass, FNTy, VK_LValue, OK_Ordinary,
495+
FNTy->isDependentType(), FNTy->isDependentType(),
496+
FNTy->isInstantiationDependentType(),
497+
/*ContainsUnexpandedParameterPack=*/false) {
498+
PredefinedExprBits.Kind = IK;
499+
assert((getIdentKind() == IK) &&
500+
"IdentKind do not fit in PredefinedExprBitfields!");
501+
assert(IK == UniqueStableNameType &&
502+
"Constructor only valid with UniqueStableNameType");
503+
PredefinedExprBits.HasFunctionName = false;
504+
PredefinedExprBits.Loc = L;
505+
setTypeSourceInfo(Info);
506+
}
507+
508+
PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
509+
Expr *Info)
510+
: Expr(PredefinedExprClass, FNTy, VK_LValue, OK_Ordinary,
511+
FNTy->isDependentType(), FNTy->isDependentType(),
512+
FNTy->isInstantiationDependentType(),
513+
/*ContainsUnexpandedParameterPack=*/false) {
514+
PredefinedExprBits.Kind = IK;
515+
assert((getIdentKind() == IK) &&
516+
"IdentKind do not fit in PredefinedExprBitfields!");
517+
assert(IK == UniqueStableNameExpr &&
518+
"Constructor only valid with UniqueStableNameExpr");
519+
PredefinedExprBits.HasFunctionName = false;
520+
PredefinedExprBits.Loc = L;
521+
setExpr(Info);
522+
}
523+
492524
PredefinedExpr::PredefinedExpr(EmptyShell Empty, bool HasFunctionName)
493525
: Expr(PredefinedExprClass, Empty) {
494526
PredefinedExprBits.HasFunctionName = HasFunctionName;
@@ -498,14 +530,43 @@ PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L,
498530
QualType FNTy, IdentKind IK,
499531
StringLiteral *SL) {
500532
bool HasFunctionName = SL != nullptr;
501-
void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(HasFunctionName),
502-
alignof(PredefinedExpr));
533+
void *Mem =
534+
Ctx.Allocate(totalSizeToAlloc<PredefExprStorage>(HasFunctionName),
535+
alignof(PredefinedExpr));
503536
return new (Mem) PredefinedExpr(L, FNTy, IK, SL);
504537
}
505538

539+
PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L,
540+
QualType FNTy, IdentKind IK,
541+
StringLiteral *SL,
542+
TypeSourceInfo *Info) {
543+
assert(IK == UniqueStableNameType && "Wrong Type");
544+
bool HasFunctionName = SL != nullptr;
545+
void *Mem =
546+
Ctx.Allocate(totalSizeToAlloc<PredefExprStorage>(1),
547+
alignof(PredefinedExpr));
548+
549+
if (HasFunctionName)
550+
return new (Mem) PredefinedExpr(L, FNTy, IK, SL);
551+
return new (Mem) PredefinedExpr(L, FNTy, IK, Info);
552+
}
553+
554+
PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L,
555+
QualType FNTy, IdentKind IK,
556+
StringLiteral *SL, Expr *E) {
557+
assert(IK == UniqueStableNameExpr && "Wrong Type");
558+
bool HasFunctionName = SL != nullptr;
559+
void *Mem =
560+
Ctx.Allocate(totalSizeToAlloc<PredefExprStorage>(1),
561+
alignof(PredefinedExpr));
562+
if (HasFunctionName)
563+
return new (Mem) PredefinedExpr(L, FNTy, IK, SL);
564+
return new (Mem) PredefinedExpr(L, FNTy, IK, E);
565+
}
566+
506567
PredefinedExpr *PredefinedExpr::CreateEmpty(const ASTContext &Ctx,
507568
bool HasFunctionName) {
508-
void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(HasFunctionName),
569+
void *Mem = Ctx.Allocate(totalSizeToAlloc<PredefExprStorage>(HasFunctionName),
509570
alignof(PredefinedExpr));
510571
return new (Mem) PredefinedExpr(EmptyShell(), HasFunctionName);
511572
}
@@ -526,12 +587,27 @@ StringRef PredefinedExpr::getIdentKindName(PredefinedExpr::IdentKind IK) {
526587
return "__FUNCSIG__";
527588
case LFuncSig:
528589
return "L__FUNCSIG__";
590+
case UniqueStableNameType:
591+
case UniqueStableNameExpr:
592+
return "__unique_stable_name";
529593
case PrettyFunctionNoVirtual:
530594
break;
531595
}
532596
llvm_unreachable("Unknown ident kind for PredefinedExpr");
533597
}
534598

599+
std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentKind IK,
600+
QualType Ty) {
601+
std::unique_ptr<MangleContext> Ctx{
602+
ItaniumMangleContext::create(Context, Context.getDiagnostics(), true)};
603+
Ty = Ty.getCanonicalType();
604+
605+
SmallString<256> Buffer;
606+
llvm::raw_svector_ostream Out(Buffer);
607+
Ctx->mangleTypeName(Ty, Out);
608+
return Buffer.str();
609+
}
610+
535611
// FIXME: Maybe this should use DeclPrinter with a special "print predefined
536612
// expr" policy instead.
537613
std::string PredefinedExpr::ComputeName(IdentKind IK, const Decl *CurrentDecl) {

0 commit comments

Comments
 (0)