[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:
Erich Keane 2020-03-18 13:45:58 -07:00
parent 7754b652b3
commit b5a034e771
14 changed files with 489 additions and 19 deletions

View File

@ -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
----------------------------------

View File

@ -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(); }

View File

@ -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 {

View File

@ -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)

View File

@ -1754,6 +1754,7 @@ private:
ExprResult ParsePostfixExpressionSuffix(ExprResult LHS);
ExprResult ParseUnaryExprOrTypeTraitExpression();
ExprResult ParseBuiltinPrimaryExpression();
ExprResult ParseUniqueStableNameExpression();
ExprResult ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
bool &isCastExpr,

View File

@ -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);

View File

@ -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) {

View File

@ -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);
}

View File

@ -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

View File

@ -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"

View File

@ -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;

View File

@ -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());
}

View File

@ -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]]
});
}

View File

@ -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>();
}