[clang] b5a034e - [SYCL] Implement __builtin_unique_stable_name.
Erich Keane via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 25 07:02:11 PDT 2020
Author: Erich Keane
Date: 2020-03-25T07:01:50-07:00
New Revision: b5a034e771d0e4d7d8e71fc545b230d98e5a1f42
URL: https://github.com/llvm/llvm-project/commit/b5a034e771d0e4d7d8e71fc545b230d98e5a1f42
DIFF: https://github.com/llvm/llvm-project/commit/b5a034e771d0e4d7d8e71fc545b230d98e5a1f42.diff
LOG: [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
Added:
clang/test/CodeGenSYCL/unique-stable-name.cpp
clang/test/ParserSYCL/unique-stable-name.cpp
Modified:
clang/docs/LanguageExtensions.rst
clang/include/clang/AST/Expr.h
clang/include/clang/AST/Mangle.h
clang/include/clang/Basic/TokenKinds.def
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/Expr.cpp
clang/lib/AST/ItaniumMangle.cpp
clang/lib/Parse/ParseExpr.cpp
clang/lib/Parse/ParseTentative.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
Removed:
################################################################################
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index f9511dc1a02f..558ce7dee653 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -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
----------------------------------
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index e27d7f04093b..fa4918272819 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -1896,13 +1896,17 @@ class StringLiteral final
/// [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 @@ 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);
@@ -1933,10 +1943,39 @@ class PredefinedExpr final
*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 @@ class PredefinedExpr final
: 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(); }
diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h
index 39e4f2335deb..2cbe6e3895bd 100644
--- a/clang/include/clang/AST/Mangle.h
+++ b/clang/include/clang/AST/Mangle.h
@@ -148,9 +148,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;
@@ -169,12 +174,15 @@ class ItaniumMangleContext : public MangleContext {
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 {
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index fec029ae995e..3b1062e48767 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -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)
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 69db747fbb90..8ba701c10c59 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -1754,6 +1754,7 @@ class Parser : public CodeCompletionHandler {
ExprResult ParsePostfixExpressionSuffix(ExprResult LHS);
ExprResult ParseUnaryExprOrTypeTraitExpression();
ExprResult ParseBuiltinPrimaryExpression();
+ ExprResult ParseUniqueStableNameExpression();
ExprResult ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
bool &isCastExpr,
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 4eaf09a3f92d..841c030cecdb 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4817,6 +4817,15 @@ class Sema final {
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);
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index b964eb604d62..b603d2ab29ee 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -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) {
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index da723ede9c89..9c1e6b503eaa 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -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);
}
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 096e295b80a6..bcd5679cb43f 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -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
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 75cc7c2912b5..bca7d021da0a 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -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"
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 373ae9752d41..7cb12ec9c405 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -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;
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index a601b92fd7bd..e2b3ebba6bbe 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -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());
}
diff --git a/clang/test/CodeGenSYCL/unique-stable-name.cpp b/clang/test/CodeGenSYCL/unique-stable-name.cpp
new file mode 100644
index 000000000000..b54c17baec35
--- /dev/null
+++ b/clang/test/CodeGenSYCL/unique-stable-name.cpp
@@ -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]]
+
+ });
+}
+
diff --git a/clang/test/ParserSYCL/unique-stable-name.cpp b/clang/test/ParserSYCL/unique-stable-name.cpp
new file mode 100644
index 000000000000..d1f1304cf8b4
--- /dev/null
+++ b/clang/test/ParserSYCL/unique-stable-name.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused %s
+
+namespace NS{};
+
+void f(int var) {
+ // expected-error at +1{{expected '(' after '__builtin_unique_stable_name'}}
+ __builtin_unique_stable_name int;
+ // expected-error at +1{{expected '(' after '__builtin_unique_stable_name'}}
+ __builtin_unique_stable_name {int};
+
+ __builtin_unique_stable_name(var);
+ // expected-error at +1{{use of undeclared identifier 'bad_var'}}
+ __builtin_unique_stable_name(bad_var);
+ // expected-error at +1{{use of undeclared identifier 'bad'}}
+ __builtin_unique_stable_name(bad::type);
+ // expected-error at +1{{no member named 'still_bad' in namespace 'NS'}}
+ __builtin_unique_stable_name(NS::still_bad);
+}
+
+template <typename T>
+void f2() {
+ // expected-error at +1{{no member named 'bad_val' in 'S'}}
+ __builtin_unique_stable_name(T::bad_val);
+ // expected-error at +1{{no type named 'bad_type' in 'S'}}
+ __builtin_unique_stable_name(typename T::bad_type);
+}
+
+struct S{};
+
+void use() {
+ // expected-note at +1{{in instantiation of}}
+ f2<S>();
+}
More information about the cfe-commits
mailing list