Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1950,6 +1950,30 @@ form of ``__builtin_operator_delete`` is currently available.
These builtins are intended for use in the implementation of ``std::allocator``
and other similar allocation libraries, and are only available in C++.

``__unique_stable_name``
------------------------

``__unique_stable_name()`` is a builtin that takes a type or expression and
produces a string literal containing a unique name for the type (or type of the
expression) that is stable across split compilations.

In cases where the split compilation needs to share a unique token for a type
across the boundary (such as in an offloading situation), this name can be used
for lookup purposes.

This builtin is superior to RTTI for this purpose for two reasons. First, this
value is computed entirely at compile time, so it can be used in constant
expressions. Second, this value encodes lambda functions based on line-number
rather than the order in which it appears in a function. This is valuable
because it is stable in cases where an unrelated lambda is introduced
conditionally in the same function.

The current implementation of this builtin uses a slightly modified Itanium
Mangler to produce the unique name. The lambda ordinal is replaced with one or
more line/column pairs in the format ``LINE->COL``, separated with a ``~``
character. Typically, only one pair will be included, however in the case of
macro expansions, the entire macro expansion stack is expressed.

Multiprecision Arithmetic Builtins
----------------------------------

Expand Down
87 changes: 74 additions & 13 deletions clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -1787,10 +1787,16 @@ class StringLiteral final
}
};

union PredefExprStorage {
Stmt *S;
Expr *E;
TypeSourceInfo *T;
};

/// [C99 6.4.2.2] - A predefined identifier such as __func__.
class PredefinedExpr final
: public Expr,
private llvm::TrailingObjects<PredefinedExpr, Stmt *> {
private llvm::TrailingObjects<PredefinedExpr, PredefExprStorage> {
friend class ASTStmtReader;
friend TrailingObjects;

Expand All @@ -1809,12 +1815,18 @@ class PredefinedExpr final
PrettyFunction,
/// The same as PrettyFunction, except that the
/// 'virtual' keyword is omitted for virtual member functions.
PrettyFunctionNoVirtual
PrettyFunctionNoVirtual,
UniqueStableNameType,
UniqueStableNameExpr,
};

private:
PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
StringLiteral *SL);
PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
TypeSourceInfo *Info);
PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
Expr *E);

explicit PredefinedExpr(EmptyShell Empty, bool HasFunctionName);

Expand All @@ -1824,14 +1836,34 @@ class PredefinedExpr final
void setFunctionName(StringLiteral *SL) {
assert(hasFunctionName() &&
"This PredefinedExpr has no storage for a function name!");
*getTrailingObjects<Stmt *>() = SL;
getTrailingObjects<PredefExprStorage>()->S = SL;
}

void setTypeSourceInfo(TypeSourceInfo *Info) {
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameType &&
"TypeSourceInfo only valid for UniqueStableName of a Type");
getTrailingObjects<PredefExprStorage>()->T = Info;
}

void setExpr(Expr *E) {
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr &&
"Expr only valid for UniqueStableName of an Expression.");
getTrailingObjects<PredefExprStorage>()->E = E;
}

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

static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L,
QualType FnTy, IdentKind IK, StringLiteral *SL,
TypeSourceInfo *Info);

static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L,
QualType FnTy, IdentKind IK, StringLiteral *SL,
Expr *E);

/// Create an empty PredefinedExpr.
static PredefinedExpr *CreateEmpty(const ASTContext &Ctx,
bool HasFunctionName);
Expand All @@ -1843,20 +1875,47 @@ class PredefinedExpr final
SourceLocation getLocation() const { return PredefinedExprBits.Loc; }
void setLocation(SourceLocation L) { PredefinedExprBits.Loc = L; }

TypeSourceInfo *getTypeSourceInfo() {
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameType &&
"TypeSourceInfo only valid for UniqueStableName of a Type");
return getTrailingObjects<PredefExprStorage>()->T;
}

const TypeSourceInfo *getTypeSourceInfo() const {
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameType &&
"TypeSourceInfo only valid for UniqueStableName of a Type");
return getTrailingObjects<PredefExprStorage>()->T;
}

Expr *getExpr() {
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr &&
"Expr only valid for UniqueStableName of an Expression.");
return getTrailingObjects<PredefExprStorage>()->E;
}

const Expr *getExpr() const {
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr &&
"Expr only valid for UniqueStableName of an Expression.");
return getTrailingObjects<PredefExprStorage>()->E;
}


StringLiteral *getFunctionName() {
return hasFunctionName()
? static_cast<StringLiteral *>(*getTrailingObjects<Stmt *>())
: nullptr;
return hasFunctionName() ? static_cast<StringLiteral *>(
getTrailingObjects<PredefExprStorage>()->S)
: nullptr;
}

const StringLiteral *getFunctionName() const {
return hasFunctionName()
? static_cast<StringLiteral *>(*getTrailingObjects<Stmt *>())
: nullptr;
return hasFunctionName() ? static_cast<StringLiteral *>(
getTrailingObjects<PredefExprStorage>()->S)
: nullptr;
}

static StringRef getIdentKindName(IdentKind IK);
static std::string ComputeName(IdentKind IK, const Decl *CurrentDecl);
static std::string ComputeName(ASTContext &Ctx, IdentKind IK,
const QualType Ty);

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

// Iterators
child_range children() {
return child_range(getTrailingObjects<Stmt *>(),
getTrailingObjects<Stmt *>() + hasFunctionName());
return child_range(&getTrailingObjects<PredefExprStorage>()->S,
&getTrailingObjects<PredefExprStorage>()->S +
hasFunctionName());
}

const_child_range children() const {
return const_child_range(getTrailingObjects<Stmt *>(),
getTrailingObjects<Stmt *>() + hasFunctionName());
return const_child_range(&getTrailingObjects<PredefExprStorage>()->S,
&getTrailingObjects<PredefExprStorage>()->S +
hasFunctionName());
}
};

Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/AST/Mangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,14 @@ class MangleContext {
};

class ItaniumMangleContext : public MangleContext {
bool IsUniqueNameMangler = false;
public:
explicit ItaniumMangleContext(ASTContext &C, DiagnosticsEngine &D)
: MangleContext(C, D, MK_Itanium) {}
explicit ItaniumMangleContext(ASTContext &C, DiagnosticsEngine &D,
bool IsUniqueNameMangler)
: MangleContext(C, D, MK_Itanium),
IsUniqueNameMangler(IsUniqueNameMangler) {}

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

bool isUniqueNameMangler() { return IsUniqueNameMangler; }

static bool classof(const MangleContext *C) {
return C->getKind() == MK_Itanium;
}

static ItaniumMangleContext *create(ASTContext &Context,
DiagnosticsEngine &Diags);
static ItaniumMangleContext *create(ASTContext &Context,
DiagnosticsEngine &Diags,
bool IsUniqueNameMangler);
};

class MicrosoftMangleContext : public MangleContext {
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,7 @@ ALIAS("__char16_t" , char16_t , KEYCXX)
ALIAS("__char32_t" , char32_t , KEYCXX)

KEYWORD(__builtin_available , KEYALL)
KEYWORD(__unique_stable_name , KEYALL)

// Clang-specific keywords enabled only in testing.
TESTING_KEYWORD(__unknown_anytype , KEYALL)
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1681,6 +1681,7 @@ class Parser : public CodeCompletionHandler {
ExprResult ParsePostfixExpressionSuffix(ExprResult LHS);
ExprResult ParseUnaryExprOrTypeTraitExpression();
ExprResult ParseBuiltinPrimaryExpression();
ExprResult ParseUniqueStableNameExpression();

ExprResult ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
bool &isCastExpr,
Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -4466,6 +4466,14 @@ class Sema {
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);

ExprResult BuildUniqueStableName(SourceLocation OpLoc,
TypeSourceInfo *Operand);
ExprResult BuildUniqueStableName(SourceLocation OpLoc, Expr *E);
ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc, SourceLocation L,
SourceLocation R, ParsedType Ty);
ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc, SourceLocation L,
SourceLocation R, Expr *Operand);

bool CheckLoopHintExpr(Expr *E, SourceLocation Loc);

ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr);
Expand Down
82 changes: 79 additions & 3 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,38 @@ PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
setFunctionName(SL);
}

PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
TypeSourceInfo *Info)
: Expr(PredefinedExprClass, FNTy, VK_LValue, OK_Ordinary,
FNTy->isDependentType(), FNTy->isDependentType(),
FNTy->isInstantiationDependentType(),
/*ContainsUnexpandedParameterPack=*/false) {
PredefinedExprBits.Kind = IK;
assert((getIdentKind() == IK) &&
"IdentKind do not fit in PredefinedExprBitfields!");
assert(IK == UniqueStableNameType &&
"Constructor only valid with UniqueStableNameType");
PredefinedExprBits.HasFunctionName = false;
PredefinedExprBits.Loc = L;
setTypeSourceInfo(Info);
}

PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
Expr *Info)
: Expr(PredefinedExprClass, FNTy, VK_LValue, OK_Ordinary,
FNTy->isDependentType(), FNTy->isDependentType(),
FNTy->isInstantiationDependentType(),
/*ContainsUnexpandedParameterPack=*/false) {
PredefinedExprBits.Kind = IK;
assert((getIdentKind() == IK) &&
"IdentKind do not fit in PredefinedExprBitfields!");
assert(IK == UniqueStableNameExpr &&
"Constructor only valid with UniqueStableNameExpr");
PredefinedExprBits.HasFunctionName = false;
PredefinedExprBits.Loc = L;
setExpr(Info);
}

PredefinedExpr::PredefinedExpr(EmptyShell Empty, bool HasFunctionName)
: Expr(PredefinedExprClass, Empty) {
PredefinedExprBits.HasFunctionName = HasFunctionName;
Expand All @@ -498,14 +530,43 @@ PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L,
QualType FNTy, IdentKind IK,
StringLiteral *SL) {
bool HasFunctionName = SL != nullptr;
void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(HasFunctionName),
alignof(PredefinedExpr));
void *Mem =
Ctx.Allocate(totalSizeToAlloc<PredefExprStorage>(HasFunctionName),
alignof(PredefinedExpr));
return new (Mem) PredefinedExpr(L, FNTy, IK, SL);
}

PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L,
QualType FNTy, IdentKind IK,
StringLiteral *SL,
TypeSourceInfo *Info) {
assert(IK == UniqueStableNameType && "Wrong Type");
bool HasFunctionName = SL != nullptr;
void *Mem =
Ctx.Allocate(totalSizeToAlloc<PredefExprStorage>(1),
alignof(PredefinedExpr));

if (HasFunctionName)
return new (Mem) PredefinedExpr(L, FNTy, IK, SL);
return new (Mem) PredefinedExpr(L, FNTy, IK, Info);
}

PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L,
QualType FNTy, IdentKind IK,
StringLiteral *SL, Expr *E) {
assert(IK == UniqueStableNameExpr && "Wrong Type");
bool HasFunctionName = SL != nullptr;
void *Mem =
Ctx.Allocate(totalSizeToAlloc<PredefExprStorage>(1),
alignof(PredefinedExpr));
if (HasFunctionName)
return new (Mem) PredefinedExpr(L, FNTy, IK, SL);
return new (Mem) PredefinedExpr(L, FNTy, IK, E);
}

PredefinedExpr *PredefinedExpr::CreateEmpty(const ASTContext &Ctx,
bool HasFunctionName) {
void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(HasFunctionName),
void *Mem = Ctx.Allocate(totalSizeToAlloc<PredefExprStorage>(HasFunctionName),
alignof(PredefinedExpr));
return new (Mem) PredefinedExpr(EmptyShell(), HasFunctionName);
}
Expand All @@ -526,12 +587,27 @@ StringRef PredefinedExpr::getIdentKindName(PredefinedExpr::IdentKind IK) {
return "__FUNCSIG__";
case LFuncSig:
return "L__FUNCSIG__";
case UniqueStableNameType:
case UniqueStableNameExpr:
return "__unique_stable_name";
case PrettyFunctionNoVirtual:
break;
}
llvm_unreachable("Unknown ident kind for PredefinedExpr");
}

std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentKind IK,
QualType Ty) {
std::unique_ptr<MangleContext> Ctx{
ItaniumMangleContext::create(Context, Context.getDiagnostics(), true)};
Ty = Ty.getCanonicalType();

SmallString<256> Buffer;
llvm::raw_svector_ostream Out(Buffer);
Ctx->mangleTypeName(Ty, Out);
return Buffer.str();
}

// FIXME: Maybe this should use DeclPrinter with a special "print predefined
// expr" policy instead.
std::string PredefinedExpr::ComputeName(IdentKind IK, const Decl *CurrentDecl) {
Expand Down
Loading