llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang @llvm/pr-subscribers-hlsl Author: Helena Kotas (hekota) <details> <summary>Changes</summary> Add `environment` parameter to Clang availability attribute. The allowed values for this parameter are a subset of values allowed in the `llvm::Triple` environment component. If the `environment` parameters is present, the declared availability attribute applies only to targets with the same platform and environment. This new parameter will be initially used for annotating HLSL functions for the `shadermodel` platform because in HLSL built-in function availability can depend not just on the shader model version (mapped to `llvm::Triple::OSType`) but also on the target shader stage (mapped to `llvm::Triple::EnvironmentType`). See example in #<!-- -->89802 and microsoft/hlsl-specs#<!-- -->204 for more details. Fixes #<!-- -->89802 --- Patch is 42.70 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/89809.diff 19 Files Affected: - (modified) clang/include/clang/Basic/Attr.td (+30-3) - (modified) clang/include/clang/Basic/AttrDocs.td (+5) - (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+2) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+5-2) - (modified) clang/include/clang/Parse/Parser.h (+3) - (modified) clang/include/clang/Sema/ParsedAttr.h (+28-14) - (modified) clang/include/clang/Sema/Sema.h (+8-7) - (modified) clang/lib/AST/DeclBase.cpp (+22-6) - (modified) clang/lib/Headers/hlsl/hlsl_intrinsics.h (+11-4) - (modified) clang/lib/Index/CommentToXML.cpp (+6) - (modified) clang/lib/Parse/ParseDecl.cpp (+19-1) - (modified) clang/lib/Sema/SemaAPINotes.cpp (+2-1) - (modified) clang/lib/Sema/SemaAvailability.cpp (+81-33) - (modified) clang/lib/Sema/SemaDecl.cpp (+1-1) - (modified) clang/lib/Sema/SemaDeclAttr.cpp (+30-9) - (modified) clang/test/Parser/attr-availability.c (+4) - (modified) clang/test/SemaHLSL/AvailabilityMarkup.hlsl (+4-4) - (added) clang/test/SemaHLSL/AvailabilityMarkupStages.hlsl (+44) - (modified) clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl (+2-2) ``````````diff diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 4408d517e70e58..251a2cf04e37d7 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -956,7 +956,7 @@ def Availability : InheritableAttr { VersionArgument<"deprecated">, VersionArgument<"obsoleted">, BoolArgument<"unavailable">, StringArgument<"message">, BoolArgument<"strict">, StringArgument<"replacement">, - IntArgument<"priority">]; + IntArgument<"priority">, IdentifierArgument<"environment">]; let AdditionalMembers = [{static llvm::StringRef getPrettyPlatformName(llvm::StringRef Platform) { return llvm::StringSwitch<llvm::StringRef>(Platform) @@ -976,7 +976,7 @@ def Availability : InheritableAttr { .Case("xros", "visionOS") .Case("xros_app_extension", "visionOS (App Extension)") .Case("swift", "Swift") - .Case("shadermodel", "HLSL ShaderModel") + .Case("shadermodel", "Shader Model") .Case("ohos", "OpenHarmony OS") .Default(llvm::StringRef()); } @@ -1016,7 +1016,34 @@ static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) { .Case("visionos_app_extension", "xros_app_extension") .Case("ShaderModel", "shadermodel") .Default(Platform); -} }]; +} +static llvm::StringRef getPrettyEnviromentName(llvm::StringRef Environment) { + return llvm::StringSwitch<llvm::StringRef>(Environment) + .Case("pixel", "pixel shader") + .Case("vertex", "vertex shader") + .Case("geometry", "geometry shader") + .Case("hull", "hull shader") + .Case("domain", "domain shader") + .Case("compute", "compute shader") + .Case("mesh", "mesh shader") + .Case("amplification", "amplification shader") + .Case("library", "shader library") + .Default(Environment); +} +static llvm::Triple::EnvironmentType getEnvironmentType(llvm::StringRef Environment) { + return llvm::StringSwitch<llvm::Triple::EnvironmentType>(Environment) + .Case("pixel", llvm::Triple::Pixel) + .Case("vertex", llvm::Triple::Vertex) + .Case("geometry", llvm::Triple::Geometry) + .Case("hull", llvm::Triple::Hull) + .Case("domain", llvm::Triple::Domain) + .Case("compute", llvm::Triple::Compute) + .Case("mesh", llvm::Triple::Mesh) + .Case("amplification", llvm::Triple::Amplification) + .Case("library", llvm::Triple::Library) + .Default(llvm::Triple::UnknownEnvironment); +} +}]; let HasCustomParsing = 1; let InheritEvenIfAlreadyPresent = 1; let Subjects = SubjectList<[Named]>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index a0bbe5861c5722..9c2f3f9e833a54 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -1593,6 +1593,11 @@ replacement=\ *string-literal* a warning about use of a deprecated declaration. The Fix-It will replace the deprecated declaration with the new declaration specified. +environment=\ *identifier* + Target environment in which this declaration is available. If present, + the availability attribute applies only to targets with the same platform + and environment. + Multiple availability attributes can be placed on a declaration, which may correspond to different platforms. For most platforms, the availability attribute with the platform corresponding to the target platform will be used; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 38174cf3549f14..31309b8cd70679 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1103,6 +1103,8 @@ def err_zero_version : Error< "version number must have non-zero major, minor, or sub-minor version">; def err_availability_expected_platform : Error< "expected a platform name, e.g., 'macos'">; +def err_availability_expected_environment : Error< + "expected an environment name, e.g., 'compute'">; // objc_bridge_related attribute def err_objcbridge_related_expected_related_class : Error< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index fdca82934cb4dc..d59615cccb341c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3827,6 +3827,9 @@ def note_cannot_use_trivial_abi_reason : Note< // Availability attribute def warn_availability_unknown_platform : Warning< "unknown platform %0 in availability macro">, InGroup<Availability>; +def warn_availability_unknown_environment : Warning< + "unknown environment %0 in availability macro">, InGroup<Availability>; + def warn_availability_version_ordering : Warning< "feature cannot be %select{introduced|deprecated|obsoleted}0 in %1 version " "%2 before it was %select{introduced|deprecated|obsoleted}3 in version %4; " @@ -3859,7 +3862,7 @@ def warn_availability_fuchsia_unavailable_minor : Warning< InGroup<Availability>; def warn_unguarded_availability : - Warning<"%0 is only available on %1 %2 or newer">, + Warning<"%0 %select{is only|is not}5 available %select{|in %4 environment }3on %1 %2 %select{or newer|}5">, InGroup<UnguardedAvailability>, DefaultIgnore; def warn_unguarded_availability_new : Warning<warn_unguarded_availability.Summary>, @@ -5855,7 +5858,7 @@ def note_availability_specified_here : Note< "%0 has been explicitly marked " "%select{unavailable|deleted|deprecated}1 here">; def note_partial_availability_specified_here : Note< - "%0 has been marked as being introduced in %1 %2 here, " + "%0 has been marked as being introduced in %1 %2 %select{|in %5 environment }4here, " "but the deployment target is %1 %3">; def note_implicitly_deleted : Note< "explicitly defaulted function was implicitly deleted here">; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index fb117bf04087ee..695ea4d7de0d90 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -151,6 +151,9 @@ class Parser : public CodeCompletionHandler { /// Identifier for "replacement". IdentifierInfo *Ident_replacement; + /// Identifier for "environment". + IdentifierInfo *Ident_environment; + /// Identifiers used by the 'external_source_symbol' attribute. IdentifierInfo *Ident_language, *Ident_defined_in, *Ident_generated_declaration, *Ident_USR; diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h index 25a5fa05b21c7d..a2b35e71795cd5 100644 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -40,6 +40,7 @@ class LangOptions; class Sema; class Stmt; class TargetInfo; +struct IdentifierLoc; /// Represents information about a change in availability for /// an entity, which is part of the encoding of the 'availability' @@ -68,12 +69,14 @@ struct AvailabilityData { AvailabilityChange Changes[NumAvailabilitySlots]; SourceLocation StrictLoc; const Expr *Replacement; + const IdentifierLoc *EnvironmentLoc; AvailabilityData(const AvailabilityChange &Introduced, const AvailabilityChange &Deprecated, - const AvailabilityChange &Obsoleted, - SourceLocation Strict, const Expr *ReplaceExpr) - : StrictLoc(Strict), Replacement(ReplaceExpr) { + const AvailabilityChange &Obsoleted, SourceLocation Strict, + const Expr *ReplaceExpr, const IdentifierLoc *EnvironmentLoc) + : StrictLoc(Strict), Replacement(ReplaceExpr), + EnvironmentLoc(EnvironmentLoc) { Changes[IntroducedSlot] = Introduced; Changes[DeprecatedSlot] = Deprecated; Changes[ObsoletedSlot] = Obsoleted; @@ -234,7 +237,7 @@ class ParsedAttr final const AvailabilityChange &deprecated, const AvailabilityChange &obsoleted, SourceLocation unavailable, const Expr *messageExpr, Form formUsed, SourceLocation strict, - const Expr *replacementExpr) + const Expr *replacementExpr, const IdentifierLoc *environmentLoc) : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, formUsed), NumArgs(1), Invalid(false), UsedAsTypeAttr(false), IsAvailability(true), IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false), @@ -243,8 +246,9 @@ class ParsedAttr final Info(ParsedAttrInfo::get(*this)) { ArgsUnion PVal(Parm); memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion)); - new (getAvailabilityData()) detail::AvailabilityData( - introduced, deprecated, obsoleted, strict, replacementExpr); + new (getAvailabilityData()) + detail::AvailabilityData(introduced, deprecated, obsoleted, strict, + replacementExpr, environmentLoc); } /// Constructor for objc_bridge_related attributes. @@ -445,6 +449,12 @@ class ParsedAttr final return getAvailabilityData()->Replacement; } + const IdentifierLoc *getEnvironment() const { + assert(getParsedKind() == AT_Availability && + "Not an availability attribute"); + return getAvailabilityData()->EnvironmentLoc; + } + const ParsedType &getMatchingCType() const { assert(getParsedKind() == AT_TypeTagForDatatype && "Not a type_tag_for_datatype attribute"); @@ -759,11 +769,13 @@ class AttributePool { const AvailabilityChange &obsoleted, SourceLocation unavailable, const Expr *MessageExpr, ParsedAttr::Form form, SourceLocation strict, - const Expr *ReplacementExpr) { + const Expr *ReplacementExpr, + IdentifierLoc *EnvironmentLoc) { void *memory = allocate(AttributeFactory::AvailabilityAllocSize); - return add(new (memory) ParsedAttr( - attrName, attrRange, scopeName, scopeLoc, Param, introduced, deprecated, - obsoleted, unavailable, MessageExpr, form, strict, ReplacementExpr)); + return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, + Param, introduced, deprecated, obsoleted, + unavailable, MessageExpr, form, strict, + ReplacementExpr, EnvironmentLoc)); } ParsedAttr *create(IdentifierInfo *attrName, SourceRange attrRange, @@ -993,10 +1005,12 @@ class ParsedAttributes : public ParsedAttributesView { const AvailabilityChange &obsoleted, SourceLocation unavailable, const Expr *MessageExpr, ParsedAttr::Form form, SourceLocation strict, - const Expr *ReplacementExpr) { - ParsedAttr *attr = pool.create( - attrName, attrRange, scopeName, scopeLoc, Param, introduced, deprecated, - obsoleted, unavailable, MessageExpr, form, strict, ReplacementExpr); + const Expr *ReplacementExpr, + IdentifierLoc *EnvironmentLoc) { + ParsedAttr *attr = + pool.create(attrName, attrRange, scopeName, scopeLoc, Param, introduced, + deprecated, obsoleted, unavailable, MessageExpr, form, + strict, ReplacementExpr, EnvironmentLoc); addAtEnd(attr); return attr; } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index aa182b15e66ecc..c511c018ba9a25 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -39,6 +39,7 @@ #include "clang/Basic/Cuda.h" #include "clang/Basic/DarwinSDKInfo.h" #include "clang/Basic/ExpressionTraits.h" +#include "clang/Basic/IdentifierTable.h" #include "clang/Basic/Module.h" #include "clang/Basic/OpenCLOptions.h" #include "clang/Basic/PragmaKinds.h" @@ -3618,13 +3619,13 @@ class Sema final : public SemaBase { bool CheckAttrTarget(const ParsedAttr &CurrAttr); bool CheckAttrNoArgs(const ParsedAttr &CurrAttr); - AvailabilityAttr * - mergeAvailabilityAttr(NamedDecl *D, const AttributeCommonInfo &CI, - IdentifierInfo *Platform, bool Implicit, - VersionTuple Introduced, VersionTuple Deprecated, - VersionTuple Obsoleted, bool IsUnavailable, - StringRef Message, bool IsStrict, StringRef Replacement, - AvailabilityMergeKind AMK, int Priority); + AvailabilityAttr *mergeAvailabilityAttr( + NamedDecl *D, const AttributeCommonInfo &CI, IdentifierInfo *Platform, + bool Implicit, VersionTuple Introduced, VersionTuple Deprecated, + VersionTuple Obsoleted, bool IsUnavailable, StringRef Message, + bool IsStrict, StringRef Replacement, AvailabilityMergeKind AMK, + int Priority, IdentifierInfo *IIEnvironment); + TypeVisibilityAttr * mergeTypeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI, TypeVisibilityAttr::VisibilityType Vis); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index c33babf8d1df3b..6210d715adea83 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -666,12 +666,28 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, // Make sure that this declaration has already been introduced. if (!A->getIntroduced().empty() && EnclosingVersion < A->getIntroduced()) { - if (Message) { - Message->clear(); - llvm::raw_string_ostream Out(*Message); - VersionTuple VTI(A->getIntroduced()); - Out << "introduced in " << PrettyPlatformName << ' ' - << VTI << HintMessage; + IdentifierInfo *IIEnv = A->getEnvironment(); + StringRef TargetEnv = + Context.getTargetInfo().getTriple().getEnvironmentName(); + StringRef EnvName = AvailabilityAttr::getPrettyEnviromentName(TargetEnv); + // Matching environment or no environment on attribute + if (!IIEnv || (!TargetEnv.empty() && IIEnv->getName() == TargetEnv)) { + if (Message) { + Message->clear(); + llvm::raw_string_ostream Out(*Message); + VersionTuple VTI(A->getIntroduced()); + Out << "introduced in " << PrettyPlatformName << " " << VTI << EnvName + << HintMessage; + } + } + // Non-matching environment or no environment on target + else { + if (Message) { + Message->clear(); + llvm::raw_string_ostream Out(*Message); + Out << "not available on " << PrettyPlatformName << " " << EnvName + << HintMessage; + } } return A->getStrict() ? AR_Unavailable : AR_NotYetIntroduced; diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 06409c6fc77417..6880e26600d0bb 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -18,14 +18,21 @@ namespace hlsl { #define _HLSL_BUILTIN_ALIAS(builtin) \ __attribute__((clang_builtin_alias(builtin))) -#define _HLSL_AVAILABILITY(environment, version) \ - __attribute__((availability(environment, introduced = version))) +#define _HLSL_AVAILABILITY(platform, version) \ + __attribute__((availability(platform, introduced = version))) +#define _HLSL_AVAILABILITY_STAGE(platform, version, stage) \ + __attribute__(( \ + availability(platform, introduced = version, environment = stage))) #ifdef __HLSL_ENABLE_16_BIT -#define _HLSL_16BIT_AVAILABILITY(environment, version) \ - __attribute__((availability(environment, introduced = version))) +#define _HLSL_16BIT_AVAILABILITY(platform, version) \ + __attribute__((availability(platform, introduced = version))) +#define _HLSL_16BIT_AVAILABILITY_STAGE(platform, version, stage) \ + __attribute__(( \ + availability(platform, introduced = version, environment = stage))) #else #define _HLSL_16BIT_AVAILABILITY(environment, version) +#define _HLSL_16BIT_AVAILABILITY_STAGE(environment, version, stage) #endif //===----------------------------------------------------------------------===// diff --git a/clang/lib/Index/CommentToXML.cpp b/clang/lib/Index/CommentToXML.cpp index 295f3f228ff79b..3372fbba438317 100644 --- a/clang/lib/Index/CommentToXML.cpp +++ b/clang/lib/Index/CommentToXML.cpp @@ -12,6 +12,7 @@ #include "clang/AST/Comment.h" #include "clang/AST/CommentVisitor.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/IdentifierTable.h" #include "clang/Basic/SourceManager.h" #include "clang/Format/Format.h" #include "clang/Index/USRGeneration.h" @@ -1052,6 +1053,11 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) { } if (AA->getUnavailable()) Result << "<Unavailable/>"; + + IdentifierInfo *Environment = AA->getEnvironment(); + if (Environment) { + Result << "<Environment>" << Environment->getName() << "</Environment>"; + } Result << "</Availability>"; } } diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 53a33fa4add54e..839098f5267e0e 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1224,6 +1224,7 @@ void Parser::ParseAvailabilityAttribute( enum { Introduced, Deprecated, Obsoleted, Unknown }; AvailabilityChange Changes[Unknown]; ExprResult MessageExpr, ReplacementExpr; + IdentifierLoc *EnvironmentLoc = nullptr; // Opening '('. BalancedDelimiterTracker T(*this, tok::l_paren); @@ -1271,6 +1272,7 @@ void Parser::ParseAvailabilityAttribute( Ident_message = PP.getIdentifierInfo("message"); Ident_strict = PP.getIdentifierInfo("strict"); Ident_replacement = PP.getIdentifierInfo("replacement"); + Ident_environment = PP.getIdentifierInfo("environment"); } // Parse the optional "strict", the optional "replacement" and the set of @@ -1318,6 +1320,13 @@ void Parser::ParseAvailabilityAttribute( continue; } + if (Keyword == Ident_environment) { + if (EnvironmentLoc != nullptr) { + Diag(KeywordLoc, diag::err_availability_redundant) + << Keyword << SourceRange(EnvironmentLoc->Loc); + } + } + if (Tok.isNot(tok::equal)) { Diag(Tok, diag::err_expected_after) << Keyword << tok::equal; SkipUntil(tok::r_paren, StopAtSemi); @@ -1339,6 +1348,15 @@ void Parser::ParseAvailabilityAttribute( continue; } } + if (Keyword == Ident_environment) { + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_availability_expected_environment); + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + EnvironmentLoc = ParseIdentifierLoc(); + continue; + } // Special handling of 'NA' only when applied to introduced or // deprecated. @@ -1420,7 +1438,7 @@ void Parser::ParseAvailabilityAttribute( SourceRange(AvailabilityLoc, T.getCloseLocation()), ScopeName, ScopeLoc, Platform, Changes[Introduced], Changes[Deprecated], Changes[Obsoleted], UnavailableLoc, MessageExpr.get(), Form, - StrictLoc, ReplacementExpr.get()); + StrictLoc, ReplacementExpr.get(), EnvironmentLoc); } /// Parse the contents of the "external_source_symbol" attribute. diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp index 4c445f28bba8c6..b904fa0b04448c 100644 --- a/clang/lib/Sema/SemaAPINotes.cpp +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -268,7 +268,8 @@ static void ProcessAPINotes(Sema &S, Decl *D, ASTAllocateString(S.Context, Info.UnavailableMsg), /*Strict=*/false, /*Replacement=*/StringRef(), - /*Priority=*/Sema::AP_Explicit); + /*Priority=*/Sema::AP_Explicit, + /*... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/89809 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits