diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 00759113775d4..8353863fdd73e 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -1766,7 +1766,7 @@ correctly in any circumstances. It can be used if: metaprogramming algorithms to be able to specify/detect types generically. - the generated kernel binary does not contain indirect calls because they - are eliminated using compiler optimizations e.g. devirtualization. + are eliminated using compiler optimizations e.g. devirtualization. - the selected target supports the function pointer like functionality e.g. most CPU targets. @@ -2311,6 +2311,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 ---------------------------------- @@ -2505,7 +2529,7 @@ Guaranteed inlined copy ``__builtin_memcpy_inline`` has been designed as a building block for efficient ``memcpy`` implementations. It is identical to ``__builtin_memcpy`` but also guarantees not to call any external functions. See LLVM IR `llvm.memcpy.inline -`_ intrinsic +`_ intrinsic for more information. This is useful to implement a custom version of ``memcpy``, implement a diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h index 04e8e2c7d2ccb..5036014222016 100644 --- a/clang/include/clang/AST/ComputeDependence.h +++ b/clang/include/clang/AST/ComputeDependence.h @@ -78,6 +78,7 @@ class MaterializeTemporaryExpr; class CXXFoldExpr; class TypeTraitExpr; class ConceptSpecializationExpr; +class UniqueStableNameExpr; class PredefinedExpr; class CallExpr; class OffsetOfExpr; @@ -165,6 +166,7 @@ ExprDependence computeDependence(TypeTraitExpr *E); ExprDependence computeDependence(ConceptSpecializationExpr *E, bool ValueDependent); +ExprDependence computeDependence(UniqueStableNameExpr *E); ExprDependence computeDependence(PredefinedExpr *E); ExprDependence computeDependence(CallExpr *E, llvm::ArrayRef PreArgs); ExprDependence computeDependence(OffsetOfExpr *E); diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index a44d06967431a..22924c81d5442 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -2037,6 +2037,112 @@ class PredefinedExpr final } }; +// This represents a use of the __builtin_unique_stable_name, which takes either +// a type-id or an expression, and at CodeGen time emits a unique string +// representation of the type (or type of the expression) in a way that permits +// us to properly encode information about the SYCL Kernels. +class UniqueStableNameExpr final + : public Expr, + private llvm::TrailingObjects { + friend class ASTStmtReader; + friend TrailingObjects; + SourceLocation OpLoc, LParen, RParen; + // Note: We store a Stmt* instead of the Expr* so that we can implement + // 'children'. + enum class ParamKind { Type, Expr }; + ParamKind Kind; + + UniqueStableNameExpr(EmptyShell Empty, QualType ResultTy, bool IsExpr); + UniqueStableNameExpr(SourceLocation OpLoc, SourceLocation LParen, + SourceLocation RParen, QualType ResultTy, + TypeSourceInfo *TSI); + UniqueStableNameExpr(SourceLocation OpLoc, SourceLocation LParen, + SourceLocation RParen, QualType ResultTy, Expr *E); + + size_t numTrailingObjects(OverloadToken) const { + return Kind == ParamKind::Type ? 1 : 0; + } + size_t numTrailingObjects(OverloadToken) const { + return Kind == ParamKind::Expr ? 1 : 0; + } + void setTypeSourceInfo(TypeSourceInfo *Ty) { + assert(Kind == ParamKind::Type && + "TypeSourceInfo only valid for UniqueStableName of a Type"); + *getTrailingObjects() = Ty; + } + void setExpr(Expr *E) { + assert(Kind == ParamKind::Expr && + "Expr only valid for UniqueStableName of an Expr"); + assert(E->isInstantiationDependent() && + "Expr type only valid if the expr is dependent"); + *getTrailingObjects() = E; + } + + void setLocation(SourceLocation L) { OpLoc = L; } + void setLParenLocation(SourceLocation L) { LParen = L; } + void setRParenLocation(SourceLocation L) { RParen = L; } + +public: + TypeSourceInfo *getTypeSourceInfo() { + assert(Kind == ParamKind::Type && + "TypeSourceInfo only valid for UniqueStableName of a Type"); + return *getTrailingObjects(); + } + + const TypeSourceInfo *getTypeSourceInfo() const { + assert(Kind == ParamKind::Type && + "TypeSourceInfo only valid for UniqueStableName of a Type"); + return *getTrailingObjects(); + } + + Expr *getExpr() { + assert(Kind == ParamKind::Expr && + "Expr only valid for UniqueStableName of an Expr"); + return static_cast(*getTrailingObjects()); + } + + const Expr *getExpr() const { + assert(Kind == ParamKind::Expr && + "Expr only valid for UniqueStableName of an Expr"); + return static_cast(*getTrailingObjects()); + } + + bool isExpr() const { return Kind == ParamKind::Expr; } + + bool isTypeSourceInfo() const { return Kind == ParamKind::Type; } + + static UniqueStableNameExpr * + Create(const ASTContext &Ctx, SourceLocation OpLoc, SourceLocation LParen, + SourceLocation RParen, TypeSourceInfo *TSI); + + static UniqueStableNameExpr *Create(const ASTContext &Ctx, + SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, Expr *E); + static UniqueStableNameExpr *CreateEmpty(const ASTContext &Ctx, bool IsExpr); + + SourceLocation getBeginLoc() const { return getLocation(); } + SourceLocation getEndLoc() const { return RParen; } + SourceLocation getLocation() const { return OpLoc; } + SourceLocation getLParenLocation() const { return LParen; } + SourceLocation getRParenLocation() const { return RParen; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UniqueStableNameExprClass; + } + + // Iterators + child_range children() { + return child_range(getTrailingObjects(), + getTrailingObjects() + isExpr()); + } + const_child_range children() const { + return const_child_range(getTrailingObjects(), + getTrailingObjects() + isExpr()); + } +}; + /// ParenExpr - This represents a parethesized expression, e.g. "(1)". This /// AST node is only formed if full location information is requested. class ParenExpr : public Expr { diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 9499564e46e0e..78c025d128371 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2636,6 +2636,12 @@ DEF_TRAVERSE_STMT(ObjCBridgedCastExpr, { DEF_TRAVERSE_STMT(ObjCAvailabilityCheckExpr, {}) DEF_TRAVERSE_STMT(ParenExpr, {}) DEF_TRAVERSE_STMT(ParenListExpr, {}) +DEF_TRAVERSE_STMT(UniqueStableNameExpr, { + if (S->isExpr()) + TRY_TO(TraverseStmt(S->getExpr())); + else + TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc())); +}) DEF_TRAVERSE_STMT(PredefinedExpr, {}) DEF_TRAVERSE_STMT(ShuffleVectorExpr, {}) DEF_TRAVERSE_STMT(ConvertVectorExpr, {}) diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index ecaf7b027e778..5998b0b4f0567 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -57,6 +57,7 @@ def CoreturnStmt : StmtNode; // Expressions def Expr : StmtNode; def PredefinedExpr : StmtNode; +def UniqueStableNameExpr : StmtNode; def DeclRefExpr : StmtNode; def IntegerLiteral : StmtNode; def FixedPointLiteral : StmtNode; diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 572ebae6618db..c60c6dbd36d29 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -699,6 +699,7 @@ 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 6f6d4697e6d09..80ae1f8e11b91 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1797,6 +1797,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 cc008e9869d24..a2f99d648346e 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5176,6 +5176,21 @@ class Sema final { ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val); + ExprResult BuildUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + TypeSourceInfo *TSI); + ExprResult BuildUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, Expr *E); + ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + ParsedType ParsedTy); + 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/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 5e5a73e730924..e88d8fb6f2206 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1960,6 +1960,9 @@ enum StmtCode { // FixedPointLiteral EXPR_FIXEDPOINT_LITERAL, + + // UniqueStableNameExpr + EXPR_UNIQUESTABLENAME, }; /// The kinds of designators that can occur in a diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index 4026fdc76fd6f..e9d30ecbc91c7 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -556,6 +556,12 @@ ExprDependence clang::computeDependence(RecoveryExpr *E) { return D; } +ExprDependence clang::computeDependence(UniqueStableNameExpr *E) { + if (E->isExpr()) + return E->getExpr()->getDependence(); + return toExprDependence(E->getTypeSourceInfo()->getType()->getDependence()); +} + ExprDependence clang::computeDependence(PredefinedExpr *E) { return toExprDependence(E->getType()->getDependence()) & ~ExprDependence::UnexpandedPack; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index a4a70befbdb31..681124d4cd78d 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -503,6 +503,68 @@ SourceLocation DeclRefExpr::getEndLoc() const { return getNameInfo().getEndLoc(); } +UniqueStableNameExpr::UniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + QualType ResultTy, + TypeSourceInfo *TSI) + : Expr(UniqueStableNameExprClass, ResultTy, VK_LValue, OK_Ordinary), + OpLoc(OpLoc), LParen(LParen), RParen(RParen), Kind(ParamKind::Type) { + setTypeSourceInfo(TSI); + // Fixme: Do we have to do anything to make this work? + setDependence(computeDependence(this)); +} + +UniqueStableNameExpr::UniqueStableNameExpr(EmptyShell Empty, QualType ResultTy, + bool IsExpr) + : Expr(UniqueStableNameExprClass, ResultTy, VK_LValue, OK_Ordinary) { + Kind = IsExpr ? ParamKind::Expr : ParamKind::Expr; +} + +UniqueStableNameExpr::UniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + QualType ResultTy, Expr *E) + : Expr(UniqueStableNameExprClass, ResultTy, VK_LValue, OK_Ordinary), + OpLoc(OpLoc), LParen(LParen), RParen(RParen), Kind(ParamKind::Expr) { + setExpr(E); + setDependence(computeDependence(this)); +} + +UniqueStableNameExpr *UniqueStableNameExpr::Create(const ASTContext &Ctx, + SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + Expr *E) { + assert(E->isInstantiationDependent() && + "Expr type only valid if the expr is dependent"); + void *Mem = Ctx.Allocate(totalSizeToAlloc(1, 0), + alignof(UniqueStableNameExpr)); + + QualType ResultTy = Ctx.getPointerType(Ctx.CharTy.withConst()); + return new (Mem) UniqueStableNameExpr(OpLoc, LParen, RParen, ResultTy, E); +} + +UniqueStableNameExpr *UniqueStableNameExpr::Create(const ASTContext &Ctx, + SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + TypeSourceInfo *TSI) { + void *Mem = Ctx.Allocate(totalSizeToAlloc(1, 0), + alignof(UniqueStableNameExpr)); + QualType ResultTy = Ctx.getPointerType(Ctx.CharTy.withConst()); + return new (Mem) UniqueStableNameExpr(OpLoc, LParen, RParen, ResultTy, TSI); +} + +UniqueStableNameExpr *UniqueStableNameExpr::CreateEmpty(const ASTContext &Ctx, + bool IsExpr) { + void *Mem = + Ctx.Allocate(totalSizeToAlloc(IsExpr, !IsExpr), + alignof(UniqueStableNameExpr)); + QualType ResultTy = Ctx.getPointerType(Ctx.CharTy.withConst()); + return new (Mem) UniqueStableNameExpr(EmptyShell(), ResultTy, IsExpr); +} + PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, StringLiteral *SL) : Expr(PredefinedExprClass, FNTy, VK_LValue, OK_Ordinary) { @@ -3308,6 +3370,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case SourceLocExprClass: case ConceptSpecializationExprClass: case RequiresExprClass: + case UniqueStableNameExprClass: // These never have a side-effect. return false; diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 0286c730ce4e3..9e4f9b0138aa8 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -433,6 +433,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CoawaitExprClass: case Expr::CoyieldExprClass: return ClassifyInternal(Ctx, cast(E)->getResumeExpr()); + case Expr::UniqueStableNameExprClass: + // TODO: ERICH! Figure out how to handle this. + break; } llvm_unreachable("unhandled expression kind in classification"); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 17bfed5d435fd..913baee46b5c7 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -15154,6 +15154,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::CoawaitExprClass: case Expr::DependentCoawaitExprClass: case Expr::CoyieldExprClass: + case Expr::UniqueStableNameExprClass: return ICEDiag(IK_NotICE, E->getBeginLoc()); case Expr::InitListExprClass: { diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 6415fcab52c1c..2c7bd4b3c20c5 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -4069,6 +4069,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, case Expr::OMPArrayShapingExprClass: case Expr::OMPIteratorExprClass: case Expr::CXXInheritedCtorInitExprClass: + case Expr::UniqueStableNameExprClass: llvm_unreachable("unexpected statement kind"); case Expr::ConstantExprClass: diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 9a7e40fd88e05..47a2137f02ceb 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1077,6 +1077,16 @@ void StmtPrinter::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node) { OS << "]"; } +void StmtPrinter::VisitUniqueStableNameExpr(UniqueStableNameExpr *Node) { + // FIXME: Is this the correct thing? + OS << "__builtin_unique_stable_name("; + if (Node->isExpr()) + PrintExpr(Node->getExpr()); + else + Node->getTypeSourceInfo()->getType().print(OS, Policy); + OS << ")"; +} + void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) { OS << PredefinedExpr::getIdentKindName(Node->getIdentKind()); } diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index fc1f8a5327244..c56d73d6d6c89 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -1190,6 +1190,17 @@ void StmtProfiler::VisitDeclRefExpr(const DeclRefExpr *S) { } } +void StmtProfiler::VisitUniqueStableNameExpr(const UniqueStableNameExpr *S) { + // TODO: ERICH: is this how this is supposed to work? I'm not sure what this + // is doing. + VisitExpr(S); + ID.AddBoolean(S->isExpr()); + if (S->isExpr()) + VisitStmt(S->getExpr()); + else + VisitType(S->getTypeSourceInfo()->getType()); +} + void StmtProfiler::VisitPredefinedExpr(const PredefinedExpr *S) { VisitExpr(S); ID.AddInteger(S->getIdentKind()); @@ -2067,7 +2078,7 @@ void StmtProfiler::VisitSizeOfPackExpr(const SizeOfPackExpr *S) { VisitDecl(S->getPack()); if (S->isPartiallySubstituted()) { auto Args = S->getPartialArguments(); - ID.AddInteger(Args.size()); + for (const auto &TA : Args) VisitTemplateArgument(TA); } else { diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index c2b47f6375b84..8fa93b3f8f44b 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1469,6 +1469,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()) { @@ -2324,6 +2327,45 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, return Operand; } +/// Parse a __builtin_unique_stable_name expression. Accepts a type-id or an +/// arbitrary expression as a parameter. +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. /// diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 54f9fb3db9e39..c7b06dace1e29 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1573,6 +1573,8 @@ CanThrowResult Sema::canThrow(const Stmt *S) { return mergeCanThrow(CT, canThrow(TS->getTryBody())); } + case Stmt::UniqueStableNameExprClass: + return CT_Cannot; case Stmt::NoStmtClass: llvm_unreachable("Invalid class for statement"); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 4c44295e7e142..4b23ce1c6e3e0 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3493,6 +3493,47 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, return PredefinedExpr::Create(Context, Loc, ResTy, IK, SL); } +ExprResult Sema::BuildUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + TypeSourceInfo *TSI) { + return UniqueStableNameExpr::Create(Context, OpLoc, LParen, RParen, TSI); +} +ExprResult Sema::BuildUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, Expr *E) { + // If this isn't dependent anymore, we know the type, so convert to a Type + // based version of the UniqueStableNameExpr. + if (E->isInstantiationDependent()) + return UniqueStableNameExpr::Create(Context, OpLoc, LParen, RParen, E); + + return UniqueStableNameExpr::Create( + Context, OpLoc, LParen, RParen, + Context.getTrivialTypeSourceInfo(E->getType())); +} + +ExprResult Sema::ActOnUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + ParsedType ParsedTy) { + TypeSourceInfo *TSI = nullptr; + QualType Ty = GetTypeFromParser(ParsedTy, &TSI); + + if (Ty.isNull()) + return ExprError(); + if (!TSI) + TSI = Context.getTrivialTypeSourceInfo(Ty, LParen); + + return BuildUniqueStableNameExpr(OpLoc, LParen, RParen, TSI); +} + +ExprResult Sema::ActOnUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + Expr *Operand) { + return BuildUniqueStableNameExpr(OpLoc, LParen, RParen, Operand); +} + 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 578a77aceeda5..bdc28b9664ce0 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1076,6 +1076,7 @@ namespace { const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH); + ExprResult TransformUniqueStableNameExpr(UniqueStableNameExpr *E); ExprResult TransformPredefinedExpr(PredefinedExpr *E); ExprResult TransformDeclRefExpr(DeclRefExpr *E); ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E); @@ -1419,6 +1420,19 @@ TemplateName TemplateInstantiator::TransformTemplateName( AllowInjectedClassName); } +ExprResult +TemplateInstantiator::TransformUniqueStableNameExpr(UniqueStableNameExpr *E) { + // Build automatically changes to the non-dependent version in the 'Expr' + // overload. + if (E->isExpr()) + return getSema().BuildUniqueStableNameExpr( + E->getLocation(), E->getLParenLocation(), E->getRParenLocation(), + E->getExpr()); + return getSema().BuildUniqueStableNameExpr( + E->getLocation(), E->getLParenLocation(), E->getRParenLocation(), + E->getTypeSourceInfo()); +} + ExprResult TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { if (!E->isTypeDependent()) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index dc1e0ef60cac3..a9f04bb1a5542 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -548,6 +548,28 @@ static void instantiateDependentAMDGPUWavesPerEUAttr( S.addAMDGPUWavesPerEUAttr(New, Attr, MinExpr, MaxExpr); } +// This doesn't take any template parameters, but we have a custom action that +// needs to happen when the kernel itself is instantiated. We need to run the +// ItaniumMangler to mark the names required to name this kernel. +static void instantiateDependentSYCLKernelAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const SYCLKernelAttr &Attr, Decl *New) { + const auto *FD = cast(New); + (void)FD; + + // Functions cannot be partially specialized, so if we are being instantiated, + // we are obviously a complete specialization. Since this attribute is only + // valid on function template declarations, we know that this is a full + // instantiation of a kernel. + + // TODO: ERICH: get the kernel object type here. + // getKernelObjectType + // TODO: ERICH: run the itanium mangler with a null-target and a callback that + // will save the lambdas we visit. + // TODO: ERICH: see the PredefinedExpr::ComputeName for an example. + New->addAttr(Attr.clone(S.getASTContext())); +} + /// Determine whether the attribute A might be relevent to the declaration D. /// If not, we can skip instantiating it. The attribute may or may not have /// been instantiated yet. @@ -723,6 +745,11 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } + if (auto *A = dyn_cast(TmplAttr)) { + instantiateDependentSYCLKernelAttr(*this, TemplateArgs, *A, New); + continue; + } + assert(!TmplAttr->isPackExpansion()); if (TmplAttr->isLateParsed() && LateAttrs) { // Late parsed attributes must be instantiated and attached after the diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 5a2013bd53a7a..4622ebf3e10c8 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2399,6 +2399,19 @@ class TreeTransform { return SEHFinallyStmt::Create(getSema().getASTContext(), Loc, Block); } + ExprResult RebuildUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, Expr *E) { + return getSema().BuildUniqueStableNameExpr(OpLoc, LParen, RParen, E); + } + + ExprResult RebuildUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + TypeSourceInfo *TSI) { + return getSema().BuildUniqueStableNameExpr(OpLoc, LParen, RParen, TSI); + } + /// Build a new predefined expression. /// /// By default, performs semantic analysis to build the new expression. @@ -10177,6 +10190,39 @@ TreeTransform::TransformConstantExpr(ConstantExpr *E) { return TransformExpr(E->getSubExpr()); } +template +ExprResult +TreeTransform::TransformUniqueStableNameExpr(UniqueStableNameExpr *E) { + if (!E->isTypeDependent()) + return E; + // We only have to handle the 'Expr' case, since the type case cannot be + // dependent. + if (E->isExpr()) { + ExprResult ER = getDerived().TransformExpr(E->getExpr()); + + if (ER.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && E->getExpr() == ER.get()) + return E; + + return getDerived().RebuildUniqueStableNameExpr( + E->getLocation(), E->getLParenLocation(), E->getRParenLocation(), + ER.get()); + } + + TypeSourceInfo *NewT = getDerived().TransformType(E->getTypeSourceInfo()); + + if (!NewT) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && E->getTypeSourceInfo() == NewT) + return E; + + return getDerived().RebuildUniqueStableNameExpr( + E->getLocation(), E->getLParenLocation(), E->getRParenLocation(), NewT); +} + template ExprResult TreeTransform::TransformPredefinedExpr(PredefinedExpr *E) { diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 30fb627c2a616..4a909c7f582f6 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -579,6 +579,21 @@ void ASTStmtReader::VisitConstantExpr(ConstantExpr *E) { E->setSubExpr(Record.readSubExpr()); } +void ASTStmtReader::VisitUniqueStableNameExpr(UniqueStableNameExpr *E) { + VisitExpr(E); + + bool IsExpr = Record.readBool(); + assert(E->isExpr() == IsExpr && "Wrong unique-stable-name trailing type"); + E->setLocation(readSourceLocation()); + E->setLParenLocation(readSourceLocation()); + E->setRParenLocation(readSourceLocation()); + + if (IsExpr) + E->setExpr(Record.readExpr()); + else + E->setTypeSourceInfo(Record.readTypeSourceInfo()); +} + void ASTStmtReader::VisitPredefinedExpr(PredefinedExpr *E) { VisitExpr(E); bool HasFunctionName = Record.readInt(); @@ -2801,6 +2816,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { /*StorageKind=*/Record[ASTStmtReader::NumExprFields])); break; + case EXPR_UNIQUESTABLENAME: + S = UniqueStableNameExpr::CreateEmpty( + Context, /*IsExpr*/ Record[ASTStmtReader::NumExprFields]); + break; + case EXPR_PREDEFINED: S = PredefinedExpr::CreateEmpty( Context, diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 063a81bbcf3f7..70e9c09b20c33 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -579,6 +579,22 @@ void ASTStmtWriter::VisitConstantExpr(ConstantExpr *E) { Code = serialization::EXPR_CONSTANT; } +void ASTStmtWriter::VisitUniqueStableNameExpr(UniqueStableNameExpr *E) { + VisitExpr(E); + + Record.writeBool(E->isExpr()); + Record.AddSourceLocation(E->getLocation()); + Record.AddSourceLocation(E->getLParenLocation()); + Record.AddSourceLocation(E->getRParenLocation()); + + if (E->isExpr()) + Record.AddStmt(E->getExpr()); + else + Record.AddTypeSourceInfo(E->getTypeSourceInfo()); + + Code = serialization::EXPR_UNIQUESTABLENAME; +} + void ASTStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) { VisitExpr(E); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index ccfc84bd7a58a..78eb644417022 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1419,6 +1419,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::OMPArraySectionExprClass: case Stmt::OMPArrayShapingExprClass: case Stmt::OMPIteratorExprClass: + case Stmt::UniqueStableNameExprClass: case Stmt::TypeTraitExprClass: { Bldr.takeNodes(Pred); ExplodedNodeSet preVisit; diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index b4822d3b1e934..08c6595fa6a59 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -338,6 +338,10 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::RecoveryExprClass: K = CXCursor_UnexposedExpr; break; + case Stmt::UniqueStableNameExprClass: + // TODO: ERICH: Figureout what a CXCursor is, and how to expose it here. + K = CXCursor_NotImplemented; + break; case Stmt::OpaqueValueExprClass: if (Expr *Src = cast(S)->getSourceExpr())