forked from OSchip/llvm-project
[SYCL] Implement __builtin_unique_stable_name.
In order to support non-user-named kernels, SYCL needs some way in the integration headers to name the kernel object themselves. Initially, the design considered just RTTI naming of the lambdas, this results in a quite unstable situation in light of some device/host macros. Additionally, this ends up needing to use RTTI, which is a burden on the implementation and typically unsupported. Instead, we've introduced a builtin, __builtin_unique_stable_name, which takes a type or expression, and results in a constexpr constant character array that uniquely represents the type (or type of the expression) being passed to it. The implementation accomplishes that simply by using a slightly modified version of the Itanium Mangling. The one exception is when mangling lambdas, instead of appending the index of the lambda in the function, it appends the macro-expansion back-trace of the lambda itself in the form LINE->COL[~LINE->COL...]. Differential Revision: https://reviews.llvm.org/D76620
This commit is contained in:
parent
7754b652b3
commit
b5a034e771
|
@ -2187,6 +2187,30 @@ argument.
|
|||
int *pb =__builtin_preserve_access_index(&v->c[3].b);
|
||||
__builtin_preserve_access_index(v->j);
|
||||
|
||||
``__builtin_unique_stable_name``
|
||||
------------------------
|
||||
|
||||
``__builtin_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
|
||||
----------------------------------
|
||||
|
||||
|
|
|
@ -1896,13 +1896,17 @@ public:
|
|||
/// [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, Stmt *, Expr *,
|
||||
TypeSourceInfo *> {
|
||||
friend class ASTStmtReader;
|
||||
friend TrailingObjects;
|
||||
|
||||
// PredefinedExpr is optionally followed by a single trailing
|
||||
// "Stmt *" for the predefined identifier. It is present if and only if
|
||||
// hasFunctionName() is true and is always a "StringLiteral *".
|
||||
// It can also be followed by a Expr* in the case of a
|
||||
// __builtin_unique_stable_name with an expression, or TypeSourceInfo * if
|
||||
// __builtin_unique_stable_name with a type.
|
||||
|
||||
public:
|
||||
enum IdentKind {
|
||||
|
@ -1915,12 +1919,18 @@ public:
|
|||
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);
|
||||
|
||||
|
@ -1933,10 +1943,39 @@ private:
|
|||
*getTrailingObjects<Stmt *>() = SL;
|
||||
}
|
||||
|
||||
void setTypeSourceInfo(TypeSourceInfo *Info) {
|
||||
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameType &&
|
||||
"TypeSourceInfo only valid for UniqueStableName of a Type");
|
||||
*getTrailingObjects<TypeSourceInfo *>() = Info;
|
||||
}
|
||||
|
||||
void setExpr(Expr *E) {
|
||||
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr &&
|
||||
"TypeSourceInfo only valid for UniqueStableName of n Expression.");
|
||||
*getTrailingObjects<Expr *>() = E;
|
||||
}
|
||||
|
||||
size_t numTrailingObjects(OverloadToken<Stmt *>) const {
|
||||
return hasFunctionName();
|
||||
}
|
||||
|
||||
size_t numTrailingObjects(OverloadToken<TypeSourceInfo *>) const {
|
||||
return getIdentKind() == UniqueStableNameType && !hasFunctionName();
|
||||
}
|
||||
size_t numTrailingObjects(OverloadToken<Expr *>) const {
|
||||
return getIdentKind() == UniqueStableNameExpr && !hasFunctionName();
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -1961,8 +2000,33 @@ public:
|
|||
: nullptr;
|
||||
}
|
||||
|
||||
TypeSourceInfo *getTypeSourceInfo() {
|
||||
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameType &&
|
||||
"TypeSourceInfo only valid for UniqueStableName of a Type");
|
||||
return *getTrailingObjects<TypeSourceInfo *>();
|
||||
}
|
||||
|
||||
const TypeSourceInfo *getTypeSourceInfo() const {
|
||||
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameType &&
|
||||
"TypeSourceInfo only valid for UniqueStableName of a Type");
|
||||
return *getTrailingObjects<TypeSourceInfo *>();
|
||||
}
|
||||
|
||||
Expr *getExpr() {
|
||||
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr &&
|
||||
"TypeSourceInfo only valid for UniqueStableName of n Expression.");
|
||||
return *getTrailingObjects<Expr *>();
|
||||
}
|
||||
|
||||
const Expr *getExpr() const {
|
||||
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr &&
|
||||
"TypeSourceInfo only valid for UniqueStableName of n Expression.");
|
||||
return *getTrailingObjects<Expr *>();
|
||||
}
|
||||
|
||||
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(); }
|
||||
|
|
|
@ -148,9 +148,14 @@ public:
|
|||
};
|
||||
|
||||
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;
|
||||
|
@ -169,12 +174,15 @@ public:
|
|||
|
||||
virtual void mangleLambdaSig(const CXXRecordDecl *Lambda, 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);
|
||||
DiagnosticsEngine &Diags,
|
||||
bool IsUniqueNameMangler = false);
|
||||
};
|
||||
|
||||
class MicrosoftMangleContext : public MangleContext {
|
||||
|
|
|
@ -674,11 +674,12 @@ ALIAS("_declspec" , __declspec , KEYMS)
|
|||
ALIAS("_pascal" , __pascal , KEYBORLAND)
|
||||
|
||||
// Clang Extensions.
|
||||
KEYWORD(__builtin_convertvector , KEYALL)
|
||||
ALIAS("__char16_t" , char16_t , KEYCXX)
|
||||
ALIAS("__char32_t" , char32_t , KEYCXX)
|
||||
KEYWORD(__builtin_bit_cast , KEYALL)
|
||||
KEYWORD(__builtin_available , KEYALL)
|
||||
KEYWORD(__builtin_convertvector , KEYALL)
|
||||
ALIAS("__char16_t" , char16_t , KEYCXX)
|
||||
ALIAS("__char32_t" , char32_t , KEYCXX)
|
||||
KEYWORD(__builtin_bit_cast , KEYALL)
|
||||
KEYWORD(__builtin_available , KEYALL)
|
||||
KEYWORD(__builtin_unique_stable_name, KEYALL)
|
||||
|
||||
// Clang-specific keywords enabled only in testing.
|
||||
TESTING_KEYWORD(__unknown_anytype , KEYALL)
|
||||
|
|
|
@ -1754,6 +1754,7 @@ private:
|
|||
ExprResult ParsePostfixExpressionSuffix(ExprResult LHS);
|
||||
ExprResult ParseUnaryExprOrTypeTraitExpression();
|
||||
ExprResult ParseBuiltinPrimaryExpression();
|
||||
ExprResult ParseUniqueStableNameExpression();
|
||||
|
||||
ExprResult ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
|
||||
bool &isCastExpr,
|
||||
|
|
|
@ -4817,6 +4817,15 @@ public:
|
|||
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
|
||||
ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);
|
||||
|
||||
ExprResult BuildUniqueStableName(SourceLocation Loc, TypeSourceInfo *Operand);
|
||||
ExprResult BuildUniqueStableName(SourceLocation Loc, Expr *E);
|
||||
ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc,
|
||||
SourceLocation LParen,
|
||||
SourceLocation RParen, ParsedType Ty);
|
||||
ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc,
|
||||
SourceLocation LParen,
|
||||
SourceLocation RParen, Expr *Operand);
|
||||
|
||||
bool CheckLoopHintExpr(Expr *E, SourceLocation Loc);
|
||||
|
||||
ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr);
|
||||
|
|
|
@ -507,6 +507,34 @@ PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
|
|||
setDependence(computeDependence(this));
|
||||
}
|
||||
|
||||
PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FnTy, IdentKind IK,
|
||||
TypeSourceInfo *Info)
|
||||
: Expr(PredefinedExprClass, FnTy, VK_LValue, OK_Ordinary) {
|
||||
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);
|
||||
setDependence(computeDependence(this));
|
||||
}
|
||||
|
||||
PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FnTy, IdentKind IK,
|
||||
Expr *Info)
|
||||
: Expr(PredefinedExprClass, FnTy, VK_LValue, OK_Ordinary) {
|
||||
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);
|
||||
setDependence(computeDependence(this));
|
||||
}
|
||||
|
||||
PredefinedExpr::PredefinedExpr(EmptyShell Empty, bool HasFunctionName)
|
||||
: Expr(PredefinedExprClass, Empty) {
|
||||
PredefinedExprBits.HasFunctionName = HasFunctionName;
|
||||
|
@ -516,15 +544,44 @@ 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<Stmt *, Expr *, TypeSourceInfo *>(HasFunctionName, 0, 0),
|
||||
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 && "Only valid with UniqueStableNameType");
|
||||
bool HasFunctionName = SL != nullptr;
|
||||
void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *, Expr *, TypeSourceInfo *>(
|
||||
HasFunctionName, 0, !HasFunctionName),
|
||||
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 && "Only valid with UniqueStableNameExpr");
|
||||
bool HasFunctionName = SL != nullptr;
|
||||
void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *, Expr *, TypeSourceInfo *>(
|
||||
HasFunctionName, !HasFunctionName, 0),
|
||||
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),
|
||||
alignof(PredefinedExpr));
|
||||
void *Mem = Ctx.Allocate(
|
||||
totalSizeToAlloc<Stmt *, Expr *, TypeSourceInfo *>(HasFunctionName, 0, 0),
|
||||
alignof(PredefinedExpr));
|
||||
return new (Mem) PredefinedExpr(EmptyShell(), HasFunctionName);
|
||||
}
|
||||
|
||||
|
@ -544,12 +601,28 @@ StringRef PredefinedExpr::getIdentKindName(PredefinedExpr::IdentKind IK) {
|
|||
return "__FUNCSIG__";
|
||||
case LFuncSig:
|
||||
return "L__FUNCSIG__";
|
||||
case UniqueStableNameType:
|
||||
case UniqueStableNameExpr:
|
||||
return "__builtin_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(), /*IsUniqueNameMangler*/ true)};
|
||||
|
||||
Ty = Ty.getCanonicalType();
|
||||
|
||||
SmallString<256> Buffer;
|
||||
llvm::raw_svector_ostream Out(Buffer);
|
||||
Ctx->mangleTypeName(Ty, Out);
|
||||
return std::string(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) {
|
||||
|
|
|
@ -127,8 +127,9 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
|
|||
|
||||
public:
|
||||
explicit ItaniumMangleContextImpl(ASTContext &Context,
|
||||
DiagnosticsEngine &Diags)
|
||||
: ItaniumMangleContext(Context, Diags) {}
|
||||
DiagnosticsEngine &Diags,
|
||||
bool IsUniqueNameMangler)
|
||||
: ItaniumMangleContext(Context, Diags, IsUniqueNameMangler) {}
|
||||
|
||||
/// @name Mangler Entry Points
|
||||
/// @{
|
||||
|
@ -1393,7 +1394,8 @@ void CXXNameMangler::mangleUnqualifiedName(GlobalDecl GD,
|
|||
// <lambda-sig> ::= <template-param-decl>* <parameter-type>+
|
||||
// # Parameter types or 'v' for 'void'.
|
||||
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) {
|
||||
if (Record->isLambda() && Record->getLambdaManglingNumber()) {
|
||||
if (Record->isLambda() && (Record->getLambdaManglingNumber() ||
|
||||
Context.isUniqueNameMangler())) {
|
||||
assert(!AdditionalAbiTags &&
|
||||
"Lambda type cannot have additional abi tags");
|
||||
mangleLambda(Record);
|
||||
|
@ -1768,6 +1770,37 @@ void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) {
|
|||
}
|
||||
}
|
||||
|
||||
// Handles the __builtin_unique_stable_name feature for lambdas. Instead of the
|
||||
// ordinal of the lambda in its mangling, this does line/column to uniquely and
|
||||
// reliably identify the lambda. Additionally, macro expansions are expressed
|
||||
// as well to prevent macros causing duplicates.
|
||||
static void mangleUniqueNameLambda(CXXNameMangler &Mangler, SourceManager &SM,
|
||||
raw_ostream &Out,
|
||||
const CXXRecordDecl *Lambda) {
|
||||
SourceLocation Loc = Lambda->getLocation();
|
||||
|
||||
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
|
||||
Mangler.mangleNumber(PLoc.getLine());
|
||||
Out << "->";
|
||||
Mangler.mangleNumber(PLoc.getColumn());
|
||||
|
||||
while(Loc.isMacroID()) {
|
||||
SourceLocation SLToPrint = Loc;
|
||||
if (SM.isMacroArgExpansion(Loc))
|
||||
SLToPrint = SM.getImmediateExpansionRange(Loc).getBegin();
|
||||
|
||||
PLoc = SM.getPresumedLoc(SM.getSpellingLoc(SLToPrint));
|
||||
Out << "~";
|
||||
Mangler.mangleNumber(PLoc.getLine());
|
||||
Out << "->";
|
||||
Mangler.mangleNumber(PLoc.getColumn());
|
||||
|
||||
Loc = SM.getImmediateMacroCallerLoc(Loc);
|
||||
if (Loc.isFileID())
|
||||
Loc = SM.getImmediateMacroCallerLoc(SLToPrint);
|
||||
}
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
|
||||
// If the context of a closure type is an initializer for a class member
|
||||
// (static or nonstatic), it is encoded in a qualified name with a final
|
||||
|
@ -1798,6 +1831,12 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
|
|||
mangleLambdaSig(Lambda);
|
||||
Out << "E";
|
||||
|
||||
if (Context.isUniqueNameMangler()) {
|
||||
mangleUniqueNameLambda(
|
||||
*this, Context.getASTContext().getSourceManager(), Out, Lambda);
|
||||
return;
|
||||
}
|
||||
|
||||
// The number is omitted for the first closure type with a given
|
||||
// <lambda-sig> in a given context; it is n-2 for the nth closure type
|
||||
// (in lexical order) with that same <lambda-sig> and context.
|
||||
|
@ -5203,7 +5242,8 @@ void ItaniumMangleContextImpl::mangleLambdaSig(const CXXRecordDecl *Lambda,
|
|||
Mangler.mangleLambdaSig(Lambda);
|
||||
}
|
||||
|
||||
ItaniumMangleContext *
|
||||
ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
|
||||
return new ItaniumMangleContextImpl(Context, Diags);
|
||||
ItaniumMangleContext *ItaniumMangleContext::create(ASTContext &Context,
|
||||
DiagnosticsEngine &Diags,
|
||||
bool IsUniqueNameMangler) {
|
||||
return new ItaniumMangleContextImpl(Context, Diags, IsUniqueNameMangler);
|
||||
}
|
||||
|
|
|
@ -1450,7 +1450,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
|
|||
case tok::kw_this:
|
||||
Res = ParseCXXThis();
|
||||
break;
|
||||
|
||||
case tok::kw___builtin_unique_stable_name:
|
||||
Res = ParseUniqueStableNameExpression();
|
||||
break;
|
||||
case tok::annot_typename:
|
||||
if (isStartOfObjCClassMessageMissingOpenBracket()) {
|
||||
ParsedType Type = getTypeAnnotation(Tok);
|
||||
|
@ -2222,6 +2224,43 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
|
|||
}
|
||||
|
||||
|
||||
ExprResult Parser::ParseUniqueStableNameExpression() {
|
||||
assert(Tok.is(tok::kw___builtin_unique_stable_name) &&
|
||||
"Not __bulitin_unique_stable_name");
|
||||
|
||||
SourceLocation OpLoc = ConsumeToken();
|
||||
BalancedDelimiterTracker T(*this, tok::l_paren);
|
||||
|
||||
// typeid expressions are always parenthesized.
|
||||
if (T.expectAndConsume(diag::err_expected_lparen_after,
|
||||
"__builtin_unique_stable_name"))
|
||||
return ExprError();
|
||||
|
||||
if (isTypeIdInParens()) {
|
||||
TypeResult Ty = ParseTypeName();
|
||||
T.consumeClose();
|
||||
|
||||
if (Ty.isInvalid())
|
||||
return ExprError();
|
||||
|
||||
return Actions.ActOnUniqueStableNameExpr(OpLoc, T.getOpenLocation(),
|
||||
T.getCloseLocation(), Ty.get());
|
||||
}
|
||||
|
||||
EnterExpressionEvaluationContext Unevaluated(
|
||||
Actions, Sema::ExpressionEvaluationContext::Unevaluated);
|
||||
ExprResult Result = ParseExpression();
|
||||
|
||||
if (Result.isInvalid()) {
|
||||
SkipUntil(tok::r_paren, StopAtSemi);
|
||||
return Result;
|
||||
}
|
||||
|
||||
T.consumeClose();
|
||||
return Actions.ActOnUniqueStableNameExpr(OpLoc, T.getOpenLocation(),
|
||||
T.getCloseLocation(), Result.get());
|
||||
}
|
||||
|
||||
/// Parse a sizeof or alignof expression.
|
||||
///
|
||||
/// \verbatim
|
||||
|
|
|
@ -1119,6 +1119,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
|
|||
case tok::kw_L__FUNCSIG__:
|
||||
case tok::kw___PRETTY_FUNCTION__:
|
||||
case tok::kw___uuidof:
|
||||
case tok::kw___builtin_unique_stable_name:
|
||||
#define TYPE_TRAIT(N,Spelling,K) \
|
||||
case tok::kw_##Spelling:
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
|
|
|
@ -3373,6 +3373,70 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
|
|||
return PredefinedExpr::Create(Context, Loc, ResTy, IK, SL);
|
||||
}
|
||||
|
||||
static std::pair<QualType, StringLiteral *>
|
||||
GetUniqueStableNameInfo(ASTContext &Context, QualType OpType,
|
||||
SourceLocation OpLoc, PredefinedExpr::IdentKind K) {
|
||||
std::pair<QualType, StringLiteral*> Result{{}, nullptr};
|
||||
|
||||
if (OpType->isDependentType()) {
|
||||
Result.first = Context.DependentTy;
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string Str = PredefinedExpr::ComputeName(Context, K, OpType);
|
||||
llvm::APInt Length(32, Str.length() + 1);
|
||||
Result.first =
|
||||
Context.adjustStringLiteralBaseType(Context.CharTy.withConst());
|
||||
Result.first = Context.getConstantArrayType(
|
||||
Result.first, Length, nullptr, ArrayType::Normal, /*IndexTypeQuals*/ 0);
|
||||
Result.second = StringLiteral::Create(Context, Str, StringLiteral::Ascii,
|
||||
/*Pascal*/ false, Result.first, OpLoc);
|
||||
return Result;
|
||||
}
|
||||
|
||||
ExprResult Sema::BuildUniqueStableName(SourceLocation OpLoc,
|
||||
TypeSourceInfo *Operand) {
|
||||
QualType ResultTy;
|
||||
StringLiteral *SL;
|
||||
std::tie(ResultTy, SL) = GetUniqueStableNameInfo(
|
||||
Context, Operand->getType(), OpLoc, PredefinedExpr::UniqueStableNameType);
|
||||
|
||||
return PredefinedExpr::Create(Context, OpLoc, ResultTy,
|
||||
PredefinedExpr::UniqueStableNameType, SL,
|
||||
Operand);
|
||||
}
|
||||
|
||||
ExprResult Sema::BuildUniqueStableName(SourceLocation OpLoc,
|
||||
Expr *E) {
|
||||
QualType ResultTy;
|
||||
StringLiteral *SL;
|
||||
std::tie(ResultTy, SL) = GetUniqueStableNameInfo(
|
||||
Context, E->getType(), OpLoc, PredefinedExpr::UniqueStableNameExpr);
|
||||
|
||||
return PredefinedExpr::Create(Context, OpLoc, ResultTy,
|
||||
PredefinedExpr::UniqueStableNameExpr, SL, E);
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnUniqueStableNameExpr(SourceLocation OpLoc,
|
||||
SourceLocation L, SourceLocation R,
|
||||
ParsedType Ty) {
|
||||
TypeSourceInfo *TInfo = nullptr;
|
||||
QualType T = GetTypeFromParser(Ty, &TInfo);
|
||||
|
||||
if (T.isNull())
|
||||
return ExprError();
|
||||
if (!TInfo)
|
||||
TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc);
|
||||
|
||||
return BuildUniqueStableName(OpLoc, TInfo);
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnUniqueStableNameExpr(SourceLocation OpLoc,
|
||||
SourceLocation L, SourceLocation R,
|
||||
Expr *E) {
|
||||
return BuildUniqueStableName(OpLoc, E);
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
|
||||
PredefinedExpr::IdentKind IK;
|
||||
|
||||
|
|
|
@ -1385,11 +1385,47 @@ TemplateName TemplateInstantiator::TransformTemplateName(
|
|||
AllowInjectedClassName);
|
||||
}
|
||||
|
||||
static ExprResult TransformUniqueStableName(TemplateInstantiator &TI,
|
||||
PredefinedExpr *E) {
|
||||
if (E->getIdentKind() == PredefinedExpr::UniqueStableNameType) {
|
||||
TypeSourceInfo *Info =
|
||||
TI.getDerived().TransformType(E->getTypeSourceInfo());
|
||||
|
||||
if (!Info)
|
||||
return ExprError();
|
||||
|
||||
if (!TI.getDerived().AlwaysRebuild() && Info == E->getTypeSourceInfo())
|
||||
return E;
|
||||
|
||||
return TI.getSema().BuildUniqueStableName(E->getLocation(), Info);
|
||||
}
|
||||
|
||||
if (E->getIdentKind() == PredefinedExpr::UniqueStableNameExpr) {
|
||||
EnterExpressionEvaluationContext Unevaluated(
|
||||
TI.getSema(), Sema::ExpressionEvaluationContext::Unevaluated);
|
||||
ExprResult SubExpr = TI.getDerived().TransformExpr(E->getExpr());
|
||||
|
||||
if (SubExpr.isInvalid())
|
||||
return ExprError();
|
||||
|
||||
if (!TI.getDerived().AlwaysRebuild() && SubExpr.get() == E->getExpr())
|
||||
return E;
|
||||
|
||||
return TI.getSema().BuildUniqueStableName(E->getLocation(), SubExpr.get());
|
||||
}
|
||||
|
||||
llvm_unreachable("Only valid for UniqueStableNameType/Expr");
|
||||
}
|
||||
|
||||
ExprResult
|
||||
TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
|
||||
if (!E->isTypeDependent())
|
||||
return E;
|
||||
|
||||
if (E->getIdentKind() == PredefinedExpr::UniqueStableNameType ||
|
||||
E->getIdentKind() == PredefinedExpr::UniqueStableNameExpr)
|
||||
return TransformUniqueStableName(*this, E);
|
||||
|
||||
return getSema().BuildPredefinedExpr(E->getLocation(), E->getIdentKind());
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
// RUN: %clang_cc1 -triple spir64-unknown-unknown-sycldevice -fsycl -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s
|
||||
// CHECK: @[[INT:[^\w]+]] = private unnamed_addr constant [[INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSi\00"
|
||||
// CHECK: @[[LAMBDA_X:[^\w]+]] = private unnamed_addr constant [[LAMBDA_X_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE42->5clEvEUlvE46->16\00"
|
||||
// CHECK: @[[MACRO_X:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE42->5clEvEUlvE52->7~28->18\00"
|
||||
// CHECK: @[[MACRO_Y:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE42->5clEvEUlvE52->7~28->41\00"
|
||||
// CHECK: @[[MACRO_MACRO_X:[^\w]+]] = private unnamed_addr constant [[MACRO_MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE42->5clEvEUlvE55->7~28->18~33->4\00"
|
||||
// CHECK: @[[MACRO_MACRO_Y:[^\w]+]] = private unnamed_addr constant [[MACRO_MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE42->5clEvEUlvE55->7~28->41~33->4\00"
|
||||
// CHECK: @[[LAMBDA_IN_DEP_INT:[^\w]+]] = private unnamed_addr constant [[DEP_INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIiEvvEUlvE23->12\00",
|
||||
// CHECK: @[[LAMBDA_IN_DEP_X:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIZZ4mainENKUlvE42->5clEvEUlvE46->16EvvEUlvE23->12\00",
|
||||
|
||||
extern "C" void printf(const char *) {}
|
||||
|
||||
template <typename T>
|
||||
void template_param() {
|
||||
printf(__builtin_unique_stable_name(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T getT() { return T{}; }
|
||||
|
||||
template <typename T>
|
||||
void lambda_in_dependent_function() {
|
||||
auto y = [] {};
|
||||
printf(__builtin_unique_stable_name(y));
|
||||
}
|
||||
|
||||
#define DEF_IN_MACRO() \
|
||||
auto MACRO_X = []() {};auto MACRO_Y = []() {}; \
|
||||
printf(__builtin_unique_stable_name(MACRO_X)); \
|
||||
printf(__builtin_unique_stable_name(MACRO_Y));
|
||||
|
||||
#define MACRO_CALLS_MACRO() \
|
||||
{DEF_IN_MACRO();}{DEF_IN_MACRO();}
|
||||
|
||||
template <typename KernelName, typename KernelType>
|
||||
[[clang::sycl_kernel]] void kernel_single_task(KernelType kernelFunc) {
|
||||
kernelFunc();
|
||||
}
|
||||
|
||||
int main() {
|
||||
kernel_single_task<class kernel>(
|
||||
[]() {
|
||||
printf(__builtin_unique_stable_name(int));
|
||||
// CHECK: call spir_func void @printf(i8* getelementptr inbounds ([[INT_SIZE]], [[INT_SIZE]]* @[[INT]]
|
||||
|
||||
auto x = [](){};
|
||||
printf(__builtin_unique_stable_name(x));
|
||||
printf(__builtin_unique_stable_name(decltype(x)));
|
||||
// CHECK: call spir_func void @printf(i8* getelementptr inbounds ([[LAMBDA_X_SIZE]], [[LAMBDA_X_SIZE]]* @[[LAMBDA_X]]
|
||||
// CHECK: call spir_func void @printf(i8* getelementptr inbounds ([[LAMBDA_X_SIZE]], [[LAMBDA_X_SIZE]]* @[[LAMBDA_X]]
|
||||
|
||||
DEF_IN_MACRO();
|
||||
// CHECK: call spir_func void @printf(i8* getelementptr inbounds ([[MACRO_SIZE]], [[MACRO_SIZE]]* @[[MACRO_X]]
|
||||
// CHECK: call spir_func void @printf(i8* getelementptr inbounds ([[MACRO_SIZE]], [[MACRO_SIZE]]* @[[MACRO_Y]]
|
||||
MACRO_CALLS_MACRO();
|
||||
// CHECK: call spir_func void @printf(i8* getelementptr inbounds ([[MACRO_MACRO_SIZE]], [[MACRO_MACRO_SIZE]]* @[[MACRO_MACRO_X]]
|
||||
// CHECK: call spir_func void @printf(i8* getelementptr inbounds ([[MACRO_MACRO_SIZE]], [[MACRO_MACRO_SIZE]]* @[[MACRO_MACRO_Y]]
|
||||
|
||||
template_param<int>();
|
||||
// CHECK: define linkonce_odr spir_func void @_Z14template_paramIiEvv
|
||||
// CHECK: call spir_func void @printf(i8* getelementptr inbounds ([[INT_SIZE]], [[INT_SIZE]]* @[[INT]]
|
||||
|
||||
template_param<decltype(x)>();
|
||||
// CHECK: define internal spir_func void @"_Z14template_paramIZZ4mainENK3
|
||||
// CHECK: call spir_func void @printf(i8* getelementptr inbounds ([[LAMBDA_X_SIZE]], [[LAMBDA_X_SIZE]]* @[[LAMBDA_X]]
|
||||
|
||||
lambda_in_dependent_function<int>();
|
||||
// CHECK: define linkonce_odr spir_func void @_Z28lambda_in_dependent_functionIiEvv
|
||||
// CHECK: call spir_func void @printf(i8* getelementptr inbounds ([[DEP_INT_SIZE]], [[DEP_INT_SIZE]]* @[[LAMBDA_IN_DEP_INT]]
|
||||
|
||||
lambda_in_dependent_function<decltype(x)>();
|
||||
// CHECK: define internal spir_func void @"_Z28lambda_in_dependent_functionIZZ4mainENK3$_0clEvEUlvE_Evv
|
||||
// CHECK: call spir_func void @printf(i8* getelementptr inbounds ([[DEP_LAMBDA_SIZE]], [[DEP_LAMBDA_SIZE]]* @[[LAMBDA_IN_DEP_X]]
|
||||
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused %s
|
||||
|
||||
namespace NS{};
|
||||
|
||||
void f(int var) {
|
||||
// expected-error@+1{{expected '(' after '__builtin_unique_stable_name'}}
|
||||
__builtin_unique_stable_name int;
|
||||
// expected-error@+1{{expected '(' after '__builtin_unique_stable_name'}}
|
||||
__builtin_unique_stable_name {int};
|
||||
|
||||
__builtin_unique_stable_name(var);
|
||||
// expected-error@+1{{use of undeclared identifier 'bad_var'}}
|
||||
__builtin_unique_stable_name(bad_var);
|
||||
// expected-error@+1{{use of undeclared identifier 'bad'}}
|
||||
__builtin_unique_stable_name(bad::type);
|
||||
// expected-error@+1{{no member named 'still_bad' in namespace 'NS'}}
|
||||
__builtin_unique_stable_name(NS::still_bad);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void f2() {
|
||||
// expected-error@+1{{no member named 'bad_val' in 'S'}}
|
||||
__builtin_unique_stable_name(T::bad_val);
|
||||
// expected-error@+1{{no type named 'bad_type' in 'S'}}
|
||||
__builtin_unique_stable_name(typename T::bad_type);
|
||||
}
|
||||
|
||||
struct S{};
|
||||
|
||||
void use() {
|
||||
// expected-note@+1{{in instantiation of}}
|
||||
f2<S>();
|
||||
}
|
Loading…
Reference in New Issue