From 4f865bb11b7b4882a6ccffb665f2e4d6aee1b3fe Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Mon, 24 Jun 2019 08:03:50 -0700 Subject: [PATCH 1/7] First attempt at __unique_stable_name This implementation uses the keyword __unique_stable_name as an operator that can take a type or expression, and will result in a constexpr constant character array that (hopefully) uniquely represents the type or type-of-expression being passed to it. The unique representation is the normal mangled name of the type, except in the cases of a lambda, where the ordinal "number" is just replaced with LINE->COL. Macro expansions are also appended with '~' followed by the LINE->COL that it appears in. For example, a lambda declared in 'main' would look like _ZTSZ4mainEUlvE25->12 (line 25, column 12). A Lambda that comes from a macro looks like: _ZTSZ4mainEUlvE45->3~18->32 (macro invoked on 45/3, lambda defined inside the macro on line 18, column 32). Template instantiations based on the lambda would result in a name that contains the lambda mangling, for example: _ZTSZ3bazIZ4mainEUlvE25->12EvvEUlvE14->12 A function template named 'baz' that is instantiated with a lambda declared in 'main' on line 25/col 12 has another macro in it, declared on line 14, column 12. Signed-off-by: Erich Keane --- clang/include/clang/AST/Expr.h | 86 ++++++++++++++++--- clang/include/clang/AST/Mangle.h | 10 +++ clang/include/clang/Basic/TokenKinds.def | 3 + clang/include/clang/Parse/Parser.h | 1 + clang/include/clang/Sema/Sema.h | 8 ++ clang/lib/AST/Expr.cpp | 80 ++++++++++++++++- clang/lib/AST/ItaniumMangle.cpp | 46 +++++++++- clang/lib/Parse/ParseExpr.cpp | 45 ++++++++++ clang/lib/Parse/ParseTentative.cpp | 1 + clang/lib/Sema/SemaExpr.cpp | 59 +++++++++++++ clang/lib/Sema/SemaTemplateInstantiate.cpp | 22 +++++ clang/test/CodeGenSYCL/unique-stable-name.cpp | 69 +++++++++++++++ 12 files changed, 413 insertions(+), 17 deletions(-) create mode 100644 clang/test/CodeGenSYCL/unique-stable-name.cpp diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 143eaae37b2af..7ea526c6328d0 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -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 { + private llvm::TrailingObjects { friend class ASTStmtReader; friend TrailingObjects; @@ -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); @@ -1824,7 +1836,18 @@ class PredefinedExpr final void setFunctionName(StringLiteral *SL) { assert(hasFunctionName() && "This PredefinedExpr has no storage for a function name!"); - *getTrailingObjects() = SL; + getTrailingObjects()->S = SL; + } + + void setTypeSourceInfo(TypeSourceInfo *Info) { + assert(!hasFunctionName() && getIdentKind() == UniqueStableNameType && + "TypeSourceInfo only valid for UniqueStableName of a Type"); + getTrailingObjects()->T = Info; + } + void setExpr(Expr *E) { + assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr && + "Expr only valid for UniqueStableName of an Expression."); + getTrailingObjects()->E = E; } public: @@ -1832,6 +1855,14 @@ class PredefinedExpr final 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); @@ -1843,20 +1874,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()->T; + } + + const TypeSourceInfo *getTypeSourceInfo() const { + assert(!hasFunctionName() && getIdentKind() == UniqueStableNameType && + "TypeSourceInfo only valid for UniqueStableName of a Type"); + return getTrailingObjects()->T; + } + + Expr *getExpr() { + assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr && + "Expr only valid for UniqueStableName of an Expression."); + return getTrailingObjects()->E; + } + + const Expr *getExpr() const { + assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr && + "TypeSourceInfo only valid for UniqueStableName of a Type"); + return getTrailingObjects()->E; + } + + StringLiteral *getFunctionName() { - return hasFunctionName() - ? static_cast(*getTrailingObjects()) - : nullptr; + return hasFunctionName() ? static_cast( + getTrailingObjects()->S) + : nullptr; } const StringLiteral *getFunctionName() const { - return hasFunctionName() - ? static_cast(*getTrailingObjects()) - : nullptr; + return hasFunctionName() ? static_cast( + getTrailingObjects()->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(); } @@ -1867,13 +1925,15 @@ class PredefinedExpr final // Iterators child_range children() { - return child_range(getTrailingObjects(), - getTrailingObjects() + hasFunctionName()); + return child_range(&getTrailingObjects()->S, + &getTrailingObjects()->S + + hasFunctionName()); } const_child_range children() const { - return const_child_range(getTrailingObjects(), - getTrailingObjects() + hasFunctionName()); + return const_child_range(&getTrailingObjects()->S, + &getTrailingObjects()->S + + hasFunctionName()); } }; diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h index fb53fbee8a06f..88ea8f29a861c 100644 --- a/clang/include/clang/AST/Mangle.h +++ b/clang/include/clang/AST/Mangle.h @@ -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; @@ -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 { diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 84807637b7d13..3ae56c488e76e 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -436,6 +436,9 @@ KEYWORD(L__FUNCSIG__ , KEYMS) TYPE_TRAIT_1(__is_interface_class, IsInterfaceClass, KEYMS) TYPE_TRAIT_1(__is_sealed, IsSealed, KEYMS) +// Extensions for SYCL. +KEYWORD(__unique_stable_name , KEYSYCL) + // MSVC12.0 / VS2013 Type Traits TYPE_TRAIT_1(__is_destructible, IsDestructible, KEYMS) TYPE_TRAIT_1(__is_trivially_destructible, IsTriviallyDestructible, KEYCXX) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 5c888f8a105cf..e8f906d9f6f12 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -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, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 8d021f7e00d49..b9ac5f7601c71 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -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); diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 10829c7007471..9748afe9423b3 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -489,6 +489,36 @@ 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 && "Wrong Thing!"); + 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 && "Wrong Thing!"); + PredefinedExprBits.HasFunctionName = false; + PredefinedExprBits.Loc = L; + setExpr(Info); +} + PredefinedExpr::PredefinedExpr(EmptyShell Empty, bool HasFunctionName) : Expr(PredefinedExprClass, Empty) { PredefinedExprBits.HasFunctionName = HasFunctionName; @@ -498,14 +528,43 @@ PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L, QualType FNTy, IdentKind IK, StringLiteral *SL) { bool HasFunctionName = SL != nullptr; - void *Mem = Ctx.Allocate(totalSizeToAlloc(HasFunctionName), - alignof(PredefinedExpr)); + void *Mem = + Ctx.Allocate(totalSizeToAlloc(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(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(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(HasFunctionName), + void *Mem = Ctx.Allocate(totalSizeToAlloc(HasFunctionName), alignof(PredefinedExpr)); return new (Mem) PredefinedExpr(EmptyShell(), HasFunctionName); } @@ -526,12 +585,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 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) { diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 505e13f5b3b39..92814eb2a07b2 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -126,6 +126,10 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext { explicit ItaniumMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags) : ItaniumMangleContext(Context, Diags) {} + explicit ItaniumMangleContextImpl(ASTContext &Context, + DiagnosticsEngine &Diags, + bool IsUniqueNameMangler) + : ItaniumMangleContext(Context, Diags, IsUniqueNameMangler) {} /// @name Mangler Entry Points /// @{ @@ -1377,7 +1381,8 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // ::= * + // # Parameter types or 'v' for 'void'. if (const CXXRecordDecl *Record = dyn_cast(TD)) { - if (Record->isLambda() && Record->getLambdaManglingNumber()) { + if (Record->isLambda() && (Record->getLambdaManglingNumber() || + Context.isUniqueNameMangler())) { assert(!AdditionalAbiTags && "Lambda type cannot have additional abi tags"); mangleLambda(Record); @@ -1699,6 +1704,33 @@ void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) { } } +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 ToPrint = Loc; + if (SM.isMacroArgExpansion(Loc)) + ToPrint = SM.getImmediateExpansionRange(Loc).getBegin(); + + Loc = SM.getImmediateMacroCallerLoc(Loc); + if (Loc.isFileID()) + Loc = SM.getImmediateMacroCallerLoc(ToPrint); + + PresumedLoc PLoc = SM.getPresumedLoc(SM.getSpellingLoc(ToPrint)); + Out << '~'; + Mangler.mangleNumber(PLoc.getLine()); + Out << "->"; + Mangler.mangleNumber(PLoc.getColumn()); + } +} + 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 @@ -1734,6 +1766,12 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { Lambda->getLambdaStaticInvoker()); 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 // in a given context; it is n-2 for the nth closure type // (in lexical order) with that same and context. @@ -5068,3 +5106,9 @@ 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 dbea7741183c3..1e622ddede9b8 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1226,6 +1226,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_typeid: Res = ParseCXXTypeid(); break; + case tok::kw___unique_stable_name: + Res = ParseUniqueStableNameExpression(); + break; case tok::kw___uuidof: Res = ParseCXXUuidof(); break; @@ -1953,6 +1956,48 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, return Operand; } +ExprResult Parser::ParseUniqueStableNameExpression() { + assert(Tok.is(tok::kw___unique_stable_name) && "Not 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, + "__unique_stable_name")) + return ExprError(); + + ExprResult Result; + + if (isTypeIdInParens()) { + TypeResult Ty = ParseTypeName(); + + // Match the ')'. + T.consumeClose(); + + if (Ty.isInvalid()) + return ExprError(); + + Result = Actions.ActOnUniqueStableNameExpr(OpLoc, T.getOpenLocation(), + T.getCloseLocation(), Ty.get()); + } else { + EnterExpressionEvaluationContext Unevaluated( + Actions, Sema::ExpressionEvaluationContext::Unevaluated); + Result = ParseExpression(); + + // Match the ')'. + if (Result.isInvalid()) + SkipUntil(tok::r_paren, StopAtSemi); + else { + T.consumeClose(); + + Result = Actions.ActOnUniqueStableNameExpr( + OpLoc, T.getOpenLocation(), T.getCloseLocation(), Result.get()); + } + } + + return Result; +} /// Parse a sizeof or alignof expression. /// diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 13d43d5e68e23..1fcc9e20a1431 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1100,6 +1100,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_L__FUNCSIG__: case tok::kw___PRETTY_FUNCTION__: case tok::kw___uuidof: + case tok::kw___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 4c8788003251e..c7bf045637a79 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3205,6 +3205,65 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, return PredefinedExpr::Create(Context, Loc, ResTy, IK, SL); } +ExprResult Sema::BuildUniqueStableName(SourceLocation OpLoc, + TypeSourceInfo *Operand) { + QualType ResultTy; + StringLiteral *SL = nullptr; + if (Operand->getType()->isDependentType()) { + ResultTy = Context.DependentTy; + } else { + std::string Str = PredefinedExpr::ComputeName(Context, + PredefinedExpr::UniqueStableNameType, Operand->getType()); + llvm::APInt Length(32, Str.length() + 1); + ResultTy = Context.adjustStringLiteralBaseType(Context.CharTy.withConst()); + ResultTy = Context.getConstantArrayType(ResultTy, Length, ArrayType::Normal, + /*IndexTypeQuals*/ 0); + SL = StringLiteral::Create(Context, Str, StringLiteral::Ascii, + /*Pascal*/ false, ResultTy, OpLoc); + } + + return PredefinedExpr::Create(Context, OpLoc, ResultTy, + PredefinedExpr::UniqueStableNameType, SL, + Operand); +} +ExprResult Sema::BuildUniqueStableName(SourceLocation OpLoc, + Expr *E) { + QualType ResultTy; + StringLiteral *SL = nullptr; + if (E->getType()->isDependentType()) { + ResultTy = Context.DependentTy; + } else { + std::string Str = PredefinedExpr::ComputeName(Context, + PredefinedExpr::UniqueStableNameExpr, E->getType()); + llvm::APInt Length(32, Str.length() + 1); + ResultTy = Context.adjustStringLiteralBaseType(Context.CharTy.withConst()); + ResultTy = Context.getConstantArrayType(ResultTy, Length, ArrayType::Normal, + /*IndexTypeQuals*/ 0); + SL = StringLiteral::Create(Context, Str, StringLiteral::Ascii, + /*Pascal*/ false, ResultTy, OpLoc); + } + + 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 ba54d5010bab4..5a8811286437f 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1181,6 +1181,28 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { if (!E->isTypeDependent()) return E; + if (E->getIdentKind() == PredefinedExpr::UniqueStableNameExpr) { + EnterExpressionEvaluationContext Unevaluated( + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); + + ExprResult SubExpr = getDerived().TransformExpr(E->getExpr()); + if (SubExpr.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getExpr()) + return E; + + return getSema().BuildUniqueStableName(E->getLocation(), SubExpr.get()); + } else if (E->getIdentKind() == PredefinedExpr::UniqueStableNameType) { + TypeSourceInfo *Info = getDerived().TransformType(E->getTypeSourceInfo()); + if (!Info) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && Info == E->getTypeSourceInfo()) + return E; + return getSema().BuildUniqueStableName(E->getLocation(), Info); + } + 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 0000000000000..751ce413a38cc --- /dev/null +++ b/clang/test/CodeGenSYCL/unique-stable-name.cpp @@ -0,0 +1,69 @@ +// RUN: %clang_cc1 -triple spir64-unknown-linux-sycldevice -fsycl-is-device -disable-llvm-passes -x c++ -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"_ZTSZZ4mainENKUlvE37->5clEvEUlvE41->16\00" +// CHECK: @[[MACRO_X:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE37->5clEvEUlvE47->7~26->18\00" +// CHECK: @[[MACRO_Y:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE37->5clEvEUlvE47->7~26->41\00" +// CHECK: @[[LAMBDA_IN_DEP_INT:[^\w]+]] = private unnamed_addr constant [[DEP_INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIiEvvEUlvE21->12\00", +// CHECK: @[[LAMBDA_IN_DEP_X:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIZZ4mainENKUlvE37->5clEvEUlvE41->16EvvEUlvE21->12\00", + +extern "C" void printf(const char*); + +template +void template_param() { + printf(__unique_stable_name(T)); +} + +template +T getT() { return T{}; } + +template +void lambda_in_dependent_function() { + auto y = [] {}; + printf(__unique_stable_name(y)); +} + +#define DEF_IN_MACRO() \ + auto MACRO_X = []() {};auto MACRO_Y = []() {}; \ + printf(__unique_stable_name(MACRO_X)); \ + printf(__unique_stable_name(MACRO_Y)); + +template +__attribute__((sycl_kernel)) void kernel_single_task(KernelType kernelFunc) { + kernelFunc(); +} + +int main() { + kernel_single_task( + []() { + printf(__unique_stable_name(int)); + // CHECK: call spir_func void @printf(i8* getelementptr inbounds ([[INT_SIZE]], [[INT_SIZE]]* @[[INT]] + + auto x = [](){}; + printf(__unique_stable_name(x)); + printf(__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]] + + template_param(); + // 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(); + // 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(); + // 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(); + // 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]] + + }); +} + From ddd09b0013aa0ec90617f1b84a0aa72affd48540 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Tue, 25 Jun 2019 13:33:05 -0700 Subject: [PATCH 2/7] Add Macro containing a Macro test case Signed-off-by: Erich Keane --- clang/test/CodeGenSYCL/unique-stable-name.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/clang/test/CodeGenSYCL/unique-stable-name.cpp b/clang/test/CodeGenSYCL/unique-stable-name.cpp index 751ce413a38cc..29c0e47eaeecc 100644 --- a/clang/test/CodeGenSYCL/unique-stable-name.cpp +++ b/clang/test/CodeGenSYCL/unique-stable-name.cpp @@ -1,10 +1,12 @@ // RUN: %clang_cc1 -triple spir64-unknown-linux-sycldevice -fsycl-is-device -disable-llvm-passes -x c++ -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"_ZTSZZ4mainENKUlvE37->5clEvEUlvE41->16\00" -// CHECK: @[[MACRO_X:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE37->5clEvEUlvE47->7~26->18\00" -// CHECK: @[[MACRO_Y:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE37->5clEvEUlvE47->7~26->41\00" -// CHECK: @[[LAMBDA_IN_DEP_INT:[^\w]+]] = private unnamed_addr constant [[DEP_INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIiEvvEUlvE21->12\00", -// CHECK: @[[LAMBDA_IN_DEP_X:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIZZ4mainENKUlvE37->5clEvEUlvE41->16EvvEUlvE21->12\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*); @@ -27,6 +29,9 @@ void lambda_in_dependent_function() { printf(__unique_stable_name(MACRO_X)); \ printf(__unique_stable_name(MACRO_Y)); +#define MACRO_CALLS_MACRO() \ + {DEF_IN_MACRO();}{DEF_IN_MACRO();} + template __attribute__((sycl_kernel)) void kernel_single_task(KernelType kernelFunc) { kernelFunc(); @@ -47,6 +52,9 @@ int main() { 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(); // CHECK: define linkonce_odr spir_func void @_Z14template_paramIiEvv From e10cd3e93907f6298a6fc84beb326fdbdd3e969e Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Thu, 27 Jun 2019 07:31:13 -0700 Subject: [PATCH 3/7] Fix else-after-return as @bader requested. Signed-off-by: Erich Keane --- clang/lib/Sema/SemaTemplateInstantiate.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 5a8811286437f..56dcc7f315f0a 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1193,7 +1193,9 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { return E; return getSema().BuildUniqueStableName(E->getLocation(), SubExpr.get()); - } else if (E->getIdentKind() == PredefinedExpr::UniqueStableNameType) { + } + + if (E->getIdentKind() == PredefinedExpr::UniqueStableNameType) { TypeSourceInfo *Info = getDerived().TransformType(E->getTypeSourceInfo()); if (!Info) return ExprError(); From 3431b5e6c3b1f2d13807d5dfbecbf775feca0da0 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Fri, 28 Jun 2019 09:34:54 -0700 Subject: [PATCH 4/7] respond to @keryell's commentsx Signed-off-by: Erich Keane --- clang/include/clang/AST/Expr.h | 1 + clang/lib/AST/Expr.cpp | 6 ++++-- clang/lib/AST/ItaniumMangle.cpp | 4 ++++ clang/lib/Sema/SemaExpr.cpp | 9 +++++---- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 7ea526c6328d0..2a7c53ccd8def 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -1844,6 +1844,7 @@ class PredefinedExpr final "TypeSourceInfo only valid for UniqueStableName of a Type"); getTrailingObjects()->T = Info; } + void setExpr(Expr *E) { assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr && "Expr only valid for UniqueStableName of an Expression."); diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 9748afe9423b3..c434d0a1d3852 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -498,7 +498,8 @@ PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, PredefinedExprBits.Kind = IK; assert((getIdentKind() == IK) && "IdentKind do not fit in PredefinedExprBitfields!"); - assert(IK == UniqueStableNameType && "Wrong Thing!"); + assert(IK == UniqueStableNameType && + "Constructor only valid with UniqueStableNameType"); PredefinedExprBits.HasFunctionName = false; PredefinedExprBits.Loc = L; setTypeSourceInfo(Info); @@ -513,7 +514,8 @@ PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, PredefinedExprBits.Kind = IK; assert((getIdentKind() == IK) && "IdentKind do not fit in PredefinedExprBitfields!"); - assert(IK == UniqueStableNameExpr && "Wrong Thing!"); + assert(IK == UniqueStableNameExpr && + "Constructor only valid with UniqueStableNameExpr"); PredefinedExprBits.HasFunctionName = false; PredefinedExprBits.Loc = L; setExpr(Info); diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 92814eb2a07b2..f761ad1558b32 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -1704,6 +1704,10 @@ void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) { } } +// Handles the __unique_stable_name feature for lambdas. Instead of the ordinal +// of the lambda in its function, this does line/column to uniquely and reliably +// identify the lambda. Additionally, Macro expansions are expanded as well to +// prevent macros causing duplicates. static void mangleUniqueNameLambda(CXXNameMangler &Mangler, SourceManager &SM, raw_ostream &Out, const CXXRecordDecl *Lambda) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c7bf045637a79..1c915f4556c3f 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3212,12 +3212,12 @@ ExprResult Sema::BuildUniqueStableName(SourceLocation OpLoc, if (Operand->getType()->isDependentType()) { ResultTy = Context.DependentTy; } else { - std::string Str = PredefinedExpr::ComputeName(Context, - PredefinedExpr::UniqueStableNameType, Operand->getType()); - llvm::APInt Length(32, Str.length() + 1); + std::string Str = PredefinedExpr::ComputeName( + Context, PredefinedExpr::UniqueStableNameType, Operand->getType()); + llvm::APInt Length(32, Str.length() + 1); ResultTy = Context.adjustStringLiteralBaseType(Context.CharTy.withConst()); ResultTy = Context.getConstantArrayType(ResultTy, Length, ArrayType::Normal, - /*IndexTypeQuals*/ 0); + /*IndexTypeQuals*/ 0); SL = StringLiteral::Create(Context, Str, StringLiteral::Ascii, /*Pascal*/ false, ResultTy, OpLoc); } @@ -3226,6 +3226,7 @@ ExprResult Sema::BuildUniqueStableName(SourceLocation OpLoc, PredefinedExpr::UniqueStableNameType, SL, Operand); } + ExprResult Sema::BuildUniqueStableName(SourceLocation OpLoc, Expr *E) { QualType ResultTy; From 23414ed71c33fd2f1aa9152e9c302b6fc335b97c Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Fri, 28 Jun 2019 11:15:58 -0700 Subject: [PATCH 5/7] Document __unique_stable_name in LanguageExtensions.rst Signed-off-by: Erich Keane --- clang/docs/LanguageExtensions.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 1e4f72902ec83..d222e3fdee180 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -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 SYCL 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 ---------------------------------- From 52641a22740a3a33a5d967c2c2aac486d22533c7 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Mon, 1 Jul 2019 06:00:15 -0700 Subject: [PATCH 6/7] Enable __unqiue_stable_name in all configs so the host can use it too Signed-off-by: Erich Keane --- clang/include/clang/Basic/TokenKinds.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 3ae56c488e76e..0c97fd1d88d92 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -437,7 +437,7 @@ TYPE_TRAIT_1(__is_interface_class, IsInterfaceClass, KEYMS) TYPE_TRAIT_1(__is_sealed, IsSealed, KEYMS) // Extensions for SYCL. -KEYWORD(__unique_stable_name , KEYSYCL) +KEYWORD(__unique_stable_name , KEYALL) // MSVC12.0 / VS2013 Type Traits TYPE_TRAIT_1(__is_destructible, IsDestructible, KEYMS) From 668ed239a980058949c52c670882bb5d0311e5c7 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Mon, 1 Jul 2019 14:17:55 -0700 Subject: [PATCH 7/7] Respond to @bader's review comments Signed-off-by: Erich Keane --- clang/docs/LanguageExtensions.rst | 2 +- clang/include/clang/AST/Expr.h | 2 +- clang/include/clang/Basic/TokenKinds.def | 4 +--- clang/lib/Sema/SemaExpr.cpp | 1 + 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index d222e3fdee180..82e715b567b3f 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -1953,7 +1953,7 @@ and other similar allocation libraries, and are only available in C++. ``__unique_stable_name`` ------------------------ -``__unique_stable_name()`` is a SYCL builtin that takes a type or expression and +``__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. diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 2a7c53ccd8def..e00cfe9564de1 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -1895,7 +1895,7 @@ class PredefinedExpr final const Expr *getExpr() const { assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr && - "TypeSourceInfo only valid for UniqueStableName of a Type"); + "Expr only valid for UniqueStableName of an Expression."); return getTrailingObjects()->E; } diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 0c97fd1d88d92..649cc7c188269 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -436,9 +436,6 @@ KEYWORD(L__FUNCSIG__ , KEYMS) TYPE_TRAIT_1(__is_interface_class, IsInterfaceClass, KEYMS) TYPE_TRAIT_1(__is_sealed, IsSealed, KEYMS) -// Extensions for SYCL. -KEYWORD(__unique_stable_name , KEYALL) - // MSVC12.0 / VS2013 Type Traits TYPE_TRAIT_1(__is_destructible, IsDestructible, KEYMS) TYPE_TRAIT_1(__is_trivially_destructible, IsTriviallyDestructible, KEYCXX) @@ -675,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) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 1c915f4556c3f..4e97122cd553c 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3205,6 +3205,7 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, return PredefinedExpr::Create(Context, Loc, ResTy, IK, SL); } + ExprResult Sema::BuildUniqueStableName(SourceLocation OpLoc, TypeSourceInfo *Operand) { QualType ResultTy;