https://github.com/hekota updated https://github.com/llvm/llvm-project/pull/89809
>From 22b67d30ca087d6a912183039c87fd1790eedfe4 Mon Sep 17 00:00:00 2001 From: Helena Kotas <heko...@microsoft.com> Date: Tue, 23 Apr 2024 00:49:28 -0700 Subject: [PATCH 1/3] Add environment parameter to clang availability attribute --- clang/include/clang/Basic/Attr.td | 33 +++++- clang/include/clang/Basic/AttrDocs.td | 2 + .../clang/Basic/DiagnosticParseKinds.td | 2 + .../clang/Basic/DiagnosticSemaKinds.td | 5 +- clang/include/clang/Parse/Parser.h | 3 + clang/include/clang/Sema/ParsedAttr.h | 40 ++++--- clang/include/clang/Sema/Sema.h | 5 +- clang/lib/AST/DeclBase.cpp | 27 ++++- clang/lib/Headers/hlsl/hlsl_intrinsics.h | 13 ++- clang/lib/Index/CommentToXML.cpp | 3 + clang/lib/Parse/ParseDecl.cpp | 20 +++- clang/lib/Sema/SemaAPINotes.cpp | 3 +- clang/lib/Sema/SemaAvailability.cpp | 109 +++++++++++++----- clang/lib/Sema/SemaDecl.cpp | 2 +- clang/lib/Sema/SemaDeclAttr.cpp | 34 ++++-- 15 files changed, 232 insertions(+), 69 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index dc87a8c6f022dc..1b07f4eb408093 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", "HLSL 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..a81163df35ca8b 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -1593,6 +1593,8 @@ replacement=\ *string-literal* a warning about use of a deprecated declaration. The Fix-It will replace the deprecated declaration with the new declaration specified. +// HEKOTA TODO add docs here + 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 66405095d51de8..631dc8880fcfc8 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., 'pixel'">; // 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 1a2d8bf4e4eb15..2647d84d4041d4 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3819,6 +3819,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; " @@ -3851,7 +3854,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>, diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 72b2f958a5e622..a6cb96ca4a37cc 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..7ad39d1a4942fa 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) { + 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 1e89dfc58d92b1..d2686e9f8bd795 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" @@ -3623,7 +3624,9 @@ class Sema final : public SemaBase { VersionTuple Introduced, VersionTuple Deprecated, VersionTuple Obsoleted, bool IsUnavailable, StringRef Message, bool IsStrict, StringRef Replacement, - AvailabilityMergeKind AMK, int Priority); + 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 434926324c96ca..87177d00c83a4d 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -666,12 +666,27 @@ 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..ca0582ef39a272 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -18,14 +18,19 @@ 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..5a484bdd15eaae 100644 --- a/clang/lib/Index/CommentToXML.cpp +++ b/clang/lib/Index/CommentToXML.cpp @@ -1052,6 +1052,9 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) { } if (AA->getUnavailable()) Result << "<Unavailable/>"; + + // HEKOTA TODO add Environment here + Result << "</Availability>"; } } diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 5f26b5a9e46bef..55facfb0099321 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, + /*Environment=*/nullptr); }, [](const Decl *D) { return llvm::find_if(D->attrs(), [](const Attr *next) -> bool { diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp index 846a31a7967309..2a24cef17b469e 100644 --- a/clang/lib/Sema/SemaAvailability.cpp +++ b/clang/lib/Sema/SemaAvailability.cpp @@ -14,19 +14,35 @@ #include "clang/AST/Decl.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/DiagnosticSema.h" +#include "clang/Basic/IdentifierTable.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" +#include "llvm/ADT/StringRef.h" #include <optional> using namespace clang; using namespace sema; +static bool hasMatchingEnvironmentOrNone(const ASTContext &Context, const AvailabilityAttr *AA) { + IdentifierInfo *IIEnvironment = AA->getEnvironment(); + auto Environment = Context.getTargetInfo().getTriple().getEnvironment(); + if (!IIEnvironment || Environment == llvm::Triple::UnknownEnvironment) + return true; + + llvm::Triple::EnvironmentType ET = + AvailabilityAttr::getEnvironmentType(IIEnvironment->getName()); + return Environment == ET; +} + static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, const Decl *D) { + AvailabilityAttr const *PartialMatch = nullptr; // Check each AvailabilityAttr to find the one for this platform. + // For multiple attributes with the same platform try to find one for this + // environment. for (const auto *A : D->attrs()) { if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) { // FIXME: this is copied from CheckAvailability. We should try to @@ -45,11 +61,15 @@ static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); // Match the platform name. - if (RealizedPlatform == TargetPlatform) - return Avail; + if (RealizedPlatform == TargetPlatform) { + // Find the best matching attribute for this environment + if (hasMatchingEnvironmentOrNone(Context, Avail)) + return Avail; + PartialMatch = Avail; + } } } - return nullptr; + return PartialMatch; } /// The diagnostic we should emit for \c D, and the declaration that @@ -118,8 +138,9 @@ ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D, /// the context of \c Ctx. For example, we should emit an unavailable diagnostic /// in a deprecated context, but not the other way around. static bool -ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, - VersionTuple DeclVersion, Decl *Ctx, +ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, + VersionTuple DeclVersion, + const IdentifierInfo* DeclEnv, Decl *Ctx, const NamedDecl *OffendingDecl) { assert(K != AR_Available && "Expected an unavailable declaration here!"); @@ -139,7 +160,7 @@ ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, auto CheckContext = [&](const Decl *C) { if (K == AR_NotYetIntroduced) { if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C)) - if (AA->getIntroduced() >= DeclVersion) + if (AA->getIntroduced() >= DeclVersion && AA->getEnvironment() == DeclEnv ) return true; } else if (K == AR_Deprecated) { if (C->isDeprecated()) @@ -343,10 +364,14 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, unsigned available_here_select_kind; VersionTuple DeclVersion; - if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl)) + const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl); + const IdentifierInfo *IIEnv = nullptr; + if (AA) { DeclVersion = AA->getIntroduced(); + IIEnv = AA->getEnvironment(); + } - if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx, + if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, IIEnv, Ctx, OffendingDecl)) return; @@ -354,8 +379,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, // The declaration can have multiple availability attributes, we are looking // at one of them. - const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl); - if (A && A->isInherited()) { + if (AA && AA->isInherited()) { for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl; Redecl = Redecl->getPreviousDecl()) { const AvailabilityAttr *AForRedecl = @@ -375,9 +399,9 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, // not specified for deployment targets >= to iOS 11 or equivalent or // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or // later. - const AvailabilityAttr *AA = - getAttrForPlatform(S.getASTContext(), OffendingDecl); + assert(AA != nullptr && "expecting valid availability attribute"); VersionTuple Introduced = AA->getIntroduced(); + bool EnvironmentMatches = hasMatchingEnvironmentOrNone(S.getASTContext(), AA); bool UseNewWarning = shouldDiagnoseAvailabilityByDefault( S.Context, S.Context.getTargetInfo().getPlatformMinVersion(), @@ -385,16 +409,25 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, unsigned Warning = UseNewWarning ? diag::warn_unguarded_availability_new : diag::warn_unguarded_availability; - std::string PlatformName(AvailabilityAttr::getPrettyPlatformName( - S.getASTContext().getTargetInfo().getPlatformName())); + const TargetInfo &TI = S.getASTContext().getTargetInfo(); + std::string PlatformName( + AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName())); + std::string TargetEnvironment(AvailabilityAttr::getPrettyEnviromentName( + TI.getTriple().getEnvironmentName())); + VersionTuple UseVersion = + EnvironmentMatches ? Introduced : TI.getTriple().getOSVersion(); + bool UseEnvironment = + (AA->getEnvironment() != nullptr && !TargetEnvironment.empty()); S.Diag(Loc, Warning) << OffendingDecl << PlatformName - << Introduced.getAsString(); + << UseVersion.getAsString() << UseEnvironment + << TargetEnvironment << !EnvironmentMatches; - S.Diag(OffendingDecl->getLocation(), - diag::note_partial_availability_specified_here) - << OffendingDecl << PlatformName << Introduced.getAsString() - << S.Context.getTargetInfo().getPlatformMinVersion().getAsString(); + if (EnvironmentMatches) + S.Diag(OffendingDecl->getLocation(), + diag::note_partial_availability_specified_here) + << OffendingDecl << PlatformName << UseVersion.getAsString() + << S.Context.getTargetInfo().getPlatformMinVersion().getAsString(); if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) { if (const auto *TD = dyn_cast<TagDecl>(Enclosing)) @@ -771,17 +804,22 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( const AvailabilityAttr *AA = getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl); + bool EnvironmentMatches = + hasMatchingEnvironmentOrNone(SemaRef.getASTContext(), AA); VersionTuple Introduced = AA->getIntroduced(); - if (AvailabilityStack.back() >= Introduced) + if (EnvironmentMatches && AvailabilityStack.back() >= Introduced) return; // If the context of this function is less available than D, we should not // emit a diagnostic. - if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx, + if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, + AA->getEnvironment(), Ctx, OffendingDecl)) return; + // HEKOTA: use different error message when !environmentMatches ? + // // We would like to emit the diagnostic even if -Wunguarded-availability is // not specified for deployment targets >= to iOS 11 or equivalent or // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or @@ -793,18 +831,27 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( ? diag::warn_unguarded_availability_new : diag::warn_unguarded_availability; - std::string PlatformName(AvailabilityAttr::getPrettyPlatformName( - SemaRef.getASTContext().getTargetInfo().getPlatformName())); + const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo(); + std::string PlatformName( + AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName())); + std::string TargetEnvironment(AvailabilityAttr::getPrettyEnviromentName( + TI.getTriple().getEnvironmentName())); + VersionTuple UseVersion = + EnvironmentMatches ? Introduced : TI.getTriple().getOSVersion(); + bool useEnvironment = + (AA->getEnvironment() != nullptr && !TargetEnvironment.empty()); SemaRef.Diag(Range.getBegin(), DiagKind) - << Range << D << PlatformName << Introduced.getAsString(); - - SemaRef.Diag(OffendingDecl->getLocation(), - diag::note_partial_availability_specified_here) - << OffendingDecl << PlatformName << Introduced.getAsString() - << SemaRef.Context.getTargetInfo() - .getPlatformMinVersion() - .getAsString(); + << Range << D << PlatformName << UseVersion.getAsString() + << useEnvironment << TargetEnvironment << !EnvironmentMatches; + + if (EnvironmentMatches) + SemaRef.Diag(OffendingDecl->getLocation(), + diag::note_partial_availability_specified_here) + << OffendingDecl << PlatformName << Introduced.getAsString() + << SemaRef.Context.getTargetInfo() + .getPlatformMinVersion() + .getAsString(); auto FixitDiag = SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index af6b3f21f15a65..a9188e69f50ee2 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2916,7 +2916,7 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, D, *AA, AA->getPlatform(), AA->isImplicit(), AA->getIntroduced(), AA->getDeprecated(), AA->getObsoleted(), AA->getUnavailable(), AA->getMessage(), AA->getStrict(), AA->getReplacement(), AMK, - AA->getPriority()); + AA->getPriority(), AA->getEnvironment()); else if (const auto *VA = dyn_cast<VisibilityAttr>(Attr)) NewAttr = S.mergeVisibilityAttr(D, *VA, VA->getVisibility()); else if (const auto *VA = dyn_cast<TypeVisibilityAttr>(Attr)) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 363ae93cb62df1..b8f704155f793b 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -26,6 +26,7 @@ #include "clang/Basic/Cuda.h" #include "clang/Basic/DarwinSDKInfo.h" #include "clang/Basic/HLSLRuntime.h" +#include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" @@ -51,6 +52,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Triple.h" #include <optional> using namespace clang; @@ -2494,7 +2496,7 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr( bool Implicit, VersionTuple Introduced, VersionTuple Deprecated, VersionTuple Obsoleted, bool IsUnavailable, StringRef Message, bool IsStrict, StringRef Replacement, AvailabilityMergeKind AMK, - int Priority) { + int Priority, IdentifierInfo *Environment) { VersionTuple MergedIntroduced = Introduced; VersionTuple MergedDeprecated = Deprecated; VersionTuple MergedObsoleted = Obsoleted; @@ -2528,6 +2530,12 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr( continue; } + IdentifierInfo *OldEnvironment = OldAA->getEnvironment(); + if (OldEnvironment != Environment) { + ++i; + continue; + } + // If there is an existing availability attribute for this platform that // has a lower priority use the existing one and discard the new // attribute. @@ -2646,7 +2654,7 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr( !OverrideOrImpl) { auto *Avail = ::new (Context) AvailabilityAttr( Context, CI, Platform, Introduced, Deprecated, Obsoleted, IsUnavailable, - Message, IsStrict, Replacement, Priority); + Message, IsStrict, Replacement, Priority, Environment); Avail->setImplicit(Implicit); return Avail; } @@ -2708,10 +2716,22 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { int PriorityModifier = AL.isPragmaClangAttribute() ? Sema::AP_PragmaClangAttribute : Sema::AP_Explicit; + + const IdentifierLoc *EnvironmentLoc = AL.getEnvironment(); + IdentifierInfo *IIEnvironment = nullptr; + if (EnvironmentLoc) { + IIEnvironment = EnvironmentLoc->Ident; + if (AvailabilityAttr::getEnvironmentType( + EnvironmentLoc->Ident->getName()) == + llvm::Triple::EnvironmentType::UnknownEnvironment) + S.Diag(Platform->Loc, diag::warn_availability_unknown_environment) + << EnvironmentLoc->Ident; + } + AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( ND, AL, II, false /*Implicit*/, Introduced.Version, Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, IsStrict, Replacement, - Sema::AMK_None, PriorityModifier); + Sema::AMK_None, PriorityModifier, IIEnvironment); if (NewAttr) D->addAttr(NewAttr); @@ -2768,7 +2788,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated, NewObsoleted, IsUnavailable, Str, IsStrict, Replacement, Sema::AMK_None, - PriorityModifier + Sema::AP_InferredFromOtherPlatform); + PriorityModifier + Sema::AP_InferredFromOtherPlatform, IIEnvironment); if (NewAttr) D->addAttr(NewAttr); } @@ -2810,7 +2830,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated, NewObsoleted, IsUnavailable, Str, IsStrict, Replacement, Sema::AMK_None, - PriorityModifier + Sema::AP_InferredFromOtherPlatform); + PriorityModifier + Sema::AP_InferredFromOtherPlatform, IIEnvironment); if (NewAttr) D->addAttr(NewAttr); } @@ -2843,7 +2863,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { MinMacCatalystVersion(Deprecated.Version), MinMacCatalystVersion(Obsoleted.Version), IsUnavailable, Str, IsStrict, Replacement, Sema::AMK_None, - PriorityModifier + Sema::AP_InferredFromOtherPlatform); + PriorityModifier + Sema::AP_InferredFromOtherPlatform, IIEnvironment); if (NewAttr) D->addAttr(NewAttr); } else if (II->getName() == "macos" && GetSDKInfo() && @@ -2886,7 +2906,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { VersionOrEmptyVersion(NewObsoleted), /*IsUnavailable=*/false, Str, IsStrict, Replacement, Sema::AMK_None, PriorityModifier + Sema::AP_InferredFromOtherPlatform + - Sema::AP_InferredFromOtherPlatform); + Sema::AP_InferredFromOtherPlatform, IIEnvironment); if (NewAttr) D->addAttr(NewAttr); } >From 36eb95468b95e3dd545f0eb7eb3eddfeb68db97e Mon Sep 17 00:00:00 2001 From: Helena Kotas <heko...@microsoft.com> Date: Tue, 23 Apr 2024 13:20:19 -0700 Subject: [PATCH 2/3] apply clang-format --- clang/include/clang/Sema/ParsedAttr.h | 8 +++---- clang/include/clang/Sema/Sema.h | 16 ++++++-------- clang/lib/AST/DeclBase.cpp | 11 +++++----- clang/lib/Headers/hlsl/hlsl_intrinsics.h | 14 ++++++------ clang/lib/Index/CommentToXML.cpp | 2 +- clang/lib/Sema/SemaAvailability.cpp | 27 ++++++++++++------------ clang/lib/Sema/SemaDeclAttr.cpp | 11 +++++----- 7 files changed, 46 insertions(+), 43 deletions(-) diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h index 7ad39d1a4942fa..a2b35e71795cd5 100644 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -73,10 +73,10 @@ struct AvailabilityData { AvailabilityData(const AvailabilityChange &Introduced, const AvailabilityChange &Deprecated, - const AvailabilityChange &Obsoleted, - SourceLocation Strict, const Expr *ReplaceExpr, - const IdentifierLoc *EnvironmentLoc) - : StrictLoc(Strict), Replacement(ReplaceExpr), EnvironmentLoc(EnvironmentLoc) { + 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; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f84c023d6f78ee..64b06b42f17ab7 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3619,15 +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, - IdentifierInfo *IIEnvironment); - + 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 fbb7f2b3ac30a9..9b9e49ec7f761e 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -667,7 +667,8 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, if (!A->getIntroduced().empty() && EnclosingVersion < A->getIntroduced()) { IdentifierInfo *IIEnv = A->getEnvironment(); - StringRef TargetEnv = Context.getTargetInfo().getTriple().getEnvironmentName(); + 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)) { @@ -675,8 +676,8 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, Message->clear(); llvm::raw_string_ostream Out(*Message); VersionTuple VTI(A->getIntroduced()); - Out << "introduced in " << PrettyPlatformName << " " - << VTI << EnvName << HintMessage; + Out << "introduced in " << PrettyPlatformName << " " << VTI << EnvName + << HintMessage; } } // Non-matching environment or no environment on target @@ -684,8 +685,8 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, if (Message) { Message->clear(); llvm::raw_string_ostream Out(*Message); - Out << "not available on " << PrettyPlatformName << " " - << EnvName << HintMessage; + Out << "not available on " << PrettyPlatformName << " " << EnvName + << HintMessage; } } diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index ca0582ef39a272..6880e26600d0bb 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -18,16 +18,18 @@ namespace hlsl { #define _HLSL_BUILTIN_ALIAS(builtin) \ __attribute__((clang_builtin_alias(builtin))) -#define _HLSL_AVAILABILITY(platform, 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))) +#define _HLSL_AVAILABILITY_STAGE(platform, version, stage) \ + __attribute__(( \ + availability(platform, introduced = version, environment = stage))) #ifdef __HLSL_ENABLE_16_BIT -#define _HLSL_16BIT_AVAILABILITY(platform, 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))) +#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) diff --git a/clang/lib/Index/CommentToXML.cpp b/clang/lib/Index/CommentToXML.cpp index 5a484bdd15eaae..498476063f0627 100644 --- a/clang/lib/Index/CommentToXML.cpp +++ b/clang/lib/Index/CommentToXML.cpp @@ -1054,7 +1054,7 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) { Result << "<Unavailable/>"; // HEKOTA TODO add Environment here - + Result << "</Availability>"; } } diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp index 2a24cef17b469e..c6b2ec6fa59beb 100644 --- a/clang/lib/Sema/SemaAvailability.cpp +++ b/clang/lib/Sema/SemaAvailability.cpp @@ -26,17 +26,18 @@ using namespace clang; using namespace sema; -static bool hasMatchingEnvironmentOrNone(const ASTContext &Context, const AvailabilityAttr *AA) { +static bool hasMatchingEnvironmentOrNone(const ASTContext &Context, + const AvailabilityAttr *AA) { IdentifierInfo *IIEnvironment = AA->getEnvironment(); auto Environment = Context.getTargetInfo().getTriple().getEnvironment(); - if (!IIEnvironment || Environment == llvm::Triple::UnknownEnvironment) + if (!IIEnvironment || Environment == llvm::Triple::UnknownEnvironment) return true; - + llvm::Triple::EnvironmentType ET = AvailabilityAttr::getEnvironmentType(IIEnvironment->getName()); return Environment == ET; } - + static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, const Decl *D) { AvailabilityAttr const *PartialMatch = nullptr; @@ -137,11 +138,9 @@ ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D, /// whether we should emit a diagnostic for \c K and \c DeclVersion in /// the context of \c Ctx. For example, we should emit an unavailable diagnostic /// in a deprecated context, but not the other way around. -static bool -ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, - VersionTuple DeclVersion, - const IdentifierInfo* DeclEnv, Decl *Ctx, - const NamedDecl *OffendingDecl) { +static bool ShouldDiagnoseAvailabilityInContext( + Sema &S, AvailabilityResult K, VersionTuple DeclVersion, + const IdentifierInfo *DeclEnv, Decl *Ctx, const NamedDecl *OffendingDecl) { assert(K != AR_Available && "Expected an unavailable declaration here!"); // If this was defined using CF_OPTIONS, etc. then ignore the diagnostic. @@ -160,7 +159,8 @@ ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, auto CheckContext = [&](const Decl *C) { if (K == AR_NotYetIntroduced) { if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C)) - if (AA->getIntroduced() >= DeclVersion && AA->getEnvironment() == DeclEnv ) + if (AA->getIntroduced() >= DeclVersion && + AA->getEnvironment() == DeclEnv) return true; } else if (K == AR_Deprecated) { if (C->isDeprecated()) @@ -401,7 +401,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, // later. assert(AA != nullptr && "expecting valid availability attribute"); VersionTuple Introduced = AA->getIntroduced(); - bool EnvironmentMatches = hasMatchingEnvironmentOrNone(S.getASTContext(), AA); + bool EnvironmentMatches = + hasMatchingEnvironmentOrNone(S.getASTContext(), AA); bool UseNewWarning = shouldDiagnoseAvailabilityByDefault( S.Context, S.Context.getTargetInfo().getPlatformMinVersion(), @@ -813,13 +814,13 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( // If the context of this function is less available than D, we should not // emit a diagnostic. - if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, + if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, AA->getEnvironment(), Ctx, OffendingDecl)) return; // HEKOTA: use different error message when !environmentMatches ? - // + // // We would like to emit the diagnostic even if -Wunguarded-availability is // not specified for deployment targets >= to iOS 11 or equivalent or // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index b8f704155f793b..8a8e2972616782 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -2787,8 +2787,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated, NewObsoleted, IsUnavailable, Str, IsStrict, Replacement, - Sema::AMK_None, - PriorityModifier + Sema::AP_InferredFromOtherPlatform, IIEnvironment); + Sema::AMK_None, PriorityModifier + Sema::AP_InferredFromOtherPlatform, + IIEnvironment); if (NewAttr) D->addAttr(NewAttr); } @@ -2829,8 +2829,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated, NewObsoleted, IsUnavailable, Str, IsStrict, Replacement, - Sema::AMK_None, - PriorityModifier + Sema::AP_InferredFromOtherPlatform, IIEnvironment); + Sema::AMK_None, PriorityModifier + Sema::AP_InferredFromOtherPlatform, + IIEnvironment); if (NewAttr) D->addAttr(NewAttr); } @@ -2906,7 +2906,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { VersionOrEmptyVersion(NewObsoleted), /*IsUnavailable=*/false, Str, IsStrict, Replacement, Sema::AMK_None, PriorityModifier + Sema::AP_InferredFromOtherPlatform + - Sema::AP_InferredFromOtherPlatform, IIEnvironment); + Sema::AP_InferredFromOtherPlatform, + IIEnvironment); if (NewAttr) D->addAttr(NewAttr); } >From 0a66eb21674bfd68d70ce0424d77f17c7e4cce58 Mon Sep 17 00:00:00 2001 From: Helena Kotas <heko...@microsoft.com> Date: Thu, 25 Apr 2024 16:57:32 -0700 Subject: [PATCH 3/3] Add tests and documentation, adjust diag messages --- clang/include/clang/Basic/Attr.td | 2 +- clang/include/clang/Basic/AttrDocs.td | 5 ++- .../clang/Basic/DiagnosticParseKinds.td | 2 +- .../clang/Basic/DiagnosticSemaKinds.td | 2 +- clang/lib/Index/CommentToXML.cpp | 7 ++- clang/lib/Sema/SemaAvailability.cpp | 12 ++--- clang/test/Parser/attr-availability.c | 4 ++ clang/test/SemaHLSL/AvailabilityMarkup.hlsl | 8 ++-- .../SemaHLSL/AvailabilityMarkupStages.hlsl | 44 +++++++++++++++++++ .../SemaHLSL/WaveBuiltinAvailability.hlsl | 4 +- 10 files changed, 72 insertions(+), 18 deletions(-) create mode 100644 clang/test/SemaHLSL/AvailabilityMarkupStages.hlsl diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index fb5b6d466c6ffe..251a2cf04e37d7 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -976,7 +976,7 @@ def Availability : InheritableAttr { .Case("xros", "visionOS") .Case("xros_app_extension", "visionOS (App Extension)") .Case("swift", "Swift") - .Case("shadermodel", "HLSL Shader Model") + .Case("shadermodel", "Shader Model") .Case("ohos", "OpenHarmony OS") .Default(llvm::StringRef()); } diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index a81163df35ca8b..9c2f3f9e833a54 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -1593,7 +1593,10 @@ replacement=\ *string-literal* a warning about use of a deprecated declaration. The Fix-It will replace the deprecated declaration with the new declaration specified. -// HEKOTA TODO add docs here +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 diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 624e7b0ecf2726..31309b8cd70679 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1104,7 +1104,7 @@ def err_zero_version : Error< 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., 'pixel'">; + "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 8ac94349d79aab..f3a9f1b90db598 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5860,7 +5860,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/lib/Index/CommentToXML.cpp b/clang/lib/Index/CommentToXML.cpp index 498476063f0627..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" @@ -1053,8 +1054,10 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) { if (AA->getUnavailable()) Result << "<Unavailable/>"; - // HEKOTA TODO add Environment here - + IdentifierInfo *Environment = AA->getEnvironment(); + if (Environment) { + Result << "<Environment>" << Environment->getName() << "</Environment>"; + } Result << "</Availability>"; } } diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp index c6b2ec6fa59beb..e0d3383bdfca98 100644 --- a/clang/lib/Sema/SemaAvailability.cpp +++ b/clang/lib/Sema/SemaAvailability.cpp @@ -428,7 +428,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, S.Diag(OffendingDecl->getLocation(), diag::note_partial_availability_specified_here) << OffendingDecl << PlatformName << UseVersion.getAsString() - << S.Context.getTargetInfo().getPlatformMinVersion().getAsString(); + << S.Context.getTargetInfo().getPlatformMinVersion().getAsString() + << UseEnvironment << TargetEnvironment; if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) { if (const auto *TD = dyn_cast<TagDecl>(Enclosing)) @@ -819,8 +820,6 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( OffendingDecl)) return; - // HEKOTA: use different error message when !environmentMatches ? - // // We would like to emit the diagnostic even if -Wunguarded-availability is // not specified for deployment targets >= to iOS 11 or equivalent or // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or @@ -839,12 +838,12 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( TI.getTriple().getEnvironmentName())); VersionTuple UseVersion = EnvironmentMatches ? Introduced : TI.getTriple().getOSVersion(); - bool useEnvironment = + bool UseEnvironment = (AA->getEnvironment() != nullptr && !TargetEnvironment.empty()); SemaRef.Diag(Range.getBegin(), DiagKind) << Range << D << PlatformName << UseVersion.getAsString() - << useEnvironment << TargetEnvironment << !EnvironmentMatches; + << UseEnvironment << TargetEnvironment << !EnvironmentMatches; if (EnvironmentMatches) SemaRef.Diag(OffendingDecl->getLocation(), @@ -852,7 +851,8 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( << OffendingDecl << PlatformName << Introduced.getAsString() << SemaRef.Context.getTargetInfo() .getPlatformMinVersion() - .getAsString(); + .getAsString() + << UseEnvironment << TargetEnvironment; auto FixitDiag = SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence) diff --git a/clang/test/Parser/attr-availability.c b/clang/test/Parser/attr-availability.c index aab0f2f3a852a9..8ba120f944a738 100644 --- a/clang/test/Parser/attr-availability.c +++ b/clang/test/Parser/attr-availability.c @@ -30,6 +30,10 @@ void f11(void) __attribute__((availability(macosx,message=u"b"))); // expected-w void f12(void) __attribute__((availability(macosx,message="a" u"b"))); // expected-warning {{encoding prefix 'u' on an unevaluated string literal has no effect}} +void f13(void) __attribute__((availability(shadermodel, introduced = 6.0, environment="pixel"))); // expected-error {{expected an environment name, e.g., 'compute'}} + +void f14(void) __attribute__((availability(shadermodel, introduced = 6.0, environment=pixel, environment=compute))); // expected-error {{redundant 'environment' availability change; only the last specified change will be used}} + enum E{ gorf __attribute__((availability(macosx,introduced=8.5, message = 10.0))), // expected-error {{expected string literal for optional message in 'availability' attribute}} garf __attribute__((availability(macosx,introduced=8.5, message))), // expected-error {{expected '=' after 'message'}} diff --git a/clang/test/SemaHLSL/AvailabilityMarkup.hlsl b/clang/test/SemaHLSL/AvailabilityMarkup.hlsl index b883957af08712..ece5ca9d3ea9fb 100644 --- a/clang/test/SemaHLSL/AvailabilityMarkup.hlsl +++ b/clang/test/SemaHLSL/AvailabilityMarkup.hlsl @@ -10,13 +10,13 @@ __attribute__((availability(shadermodel, introduced = 5.0))) unsigned fn5_0(); void fn() { - // expected-warning@#fn6_0_site {{'fn6_0' is only available on HLSL ShaderModel 6.0 or newer}} - // expected-note@#fn6_0 {{'fn6_0' has been marked as being introduced in HLSL ShaderModel 6.0 here, but the deployment target is HLSL ShaderModel 5.0}} + // expected-warning@#fn6_0_site {{'fn6_0' is only available on Shader Model 6.0 or newer}} + // expected-note@#fn6_0 {{'fn6_0' has been marked as being introduced in Shader Model 6.0 here, but the deployment target is Shader Model 5.0}} // expected-note@#fn6_0_site {{enclose 'fn6_0' in a __builtin_available check to silence this warning}} unsigned A = fn6_0(); // #fn6_0_site - // expected-warning@#fn5_1_site {{'fn5_1' is only available on HLSL ShaderModel 5.1 or newer}} - // expected-note@#fn5_1 {{'fn5_1' has been marked as being introduced in HLSL ShaderModel 5.1 here, but the deployment target is HLSL ShaderModel 5.0}} + // expected-warning@#fn5_1_site {{'fn5_1' is only available on Shader Model 5.1 or newer}} + // expected-note@#fn5_1 {{'fn5_1' has been marked as being introduced in Shader Model 5.1 here, but the deployment target is Shader Model 5.0}} // expected-note@#fn5_1_site {{enclose 'fn5_1' in a __builtin_available check to silence this warning}} unsigned B = fn5_1(); // #fn5_1_site diff --git a/clang/test/SemaHLSL/AvailabilityMarkupStages.hlsl b/clang/test/SemaHLSL/AvailabilityMarkupStages.hlsl new file mode 100644 index 00000000000000..ae3c2602423395 --- /dev/null +++ b/clang/test/SemaHLSL/AvailabilityMarkupStages.hlsl @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -triple dxil-unknown-shadermodel5.0-compute -verify %s + +__attribute__((availability(shadermodel, introduced = 2.0, environment = pixel))) +__attribute__((availability(shadermodel, introduced = 6.0))) +unsigned fn6_0_all(); // #fn6_0_all_def + +__attribute__((availability(shadermodel, introduced = 2.0, environment = pixel))) +__attribute__((availability(shadermodel, introduced = 5.0))) +unsigned fn5_0_all(); + +__attribute__((availability(shadermodel, introduced = 2.0, environment = pixel))) +__attribute__((availability(shadermodel, introduced = 6.0, environment = compute))) +__attribute__((availability(shadermodel, introduced = 5.0, environment = mesh))) +unsigned fn6_0_stages1(); // #fn6_0_stages1_def + +__attribute__((availability(shadermodel, introduced = 2.0, environment = pixel))) +__attribute__((availability(shadermodel, introduced = 6.0, environment = mesh))) +unsigned fn6_0_stages2(); // #fn6_0_stages2_def + +__attribute__((availability(shadermodel, introduced = 2.0, environment = pixel))) +__attribute__((availability(shadermodel, introduced = 5.0, environment = compute))) +__attribute__((availability(shadermodel, introduced = 6.0, environment = mesh))) +unsigned fn5_0_stages(); + +void fn() { + + // expected-warning@#fn6_0_all_call {{'fn6_0_all' is only available on Shader Model 6.0 or newer}} + // expected-note@#fn6_0_all_def {{'fn6_0_all' has been marked as being introduced in Shader Model 6.0 here, but the deployment target is Shader Model 5.0}} + // expected-note@#fn6_0_all_call {{enclose 'fn6_0_all' in a __builtin_available check to silence this warning}} + unsigned A = fn6_0_all(); // #fn6_0_all_call + + unsigned B = fn5_0_all(); + + // expected-warning@#fn6_0_stages1_call {{'fn6_0_stages1' is only available in compute shader environment on Shader Model 6.0 or newer}} + // expected-note@#fn6_0_stages1_def {{'fn6_0_stages1' has been marked as being introduced in Shader Model 6.0 in compute shader environment here, but the deployment target is Shader Model 5.0}} + // expected-note@#fn6_0_stages1_call {{enclose 'fn6_0_stages1' in a __builtin_available check to silence this warning}} + unsigned C = fn6_0_stages1(); // #fn6_0_stages1_call + + // expected-warning@#fn6_0_stages2_call {{'fn6_0_stages2' is not available in compute shader environment on Shader Model 5.0}} + // expected-note@#fn6_0_stages2_call {{enclose 'fn6_0_stages2' in a __builtin_available check to silence this warning}} + unsigned E = fn6_0_stages2(); // #fn6_0_stages2_call + + unsigned D = fn5_0_stages(); +} diff --git a/clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl b/clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl index 0e45edc6a4c860..185b79be37be5b 100644 --- a/clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl +++ b/clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl @@ -2,8 +2,8 @@ // WaveActiveCountBits is unavailable before ShaderModel 6.0. unsigned foo(bool b) { - // expected-warning@#site {{'WaveActiveCountBits' is only available on HLSL ShaderModel 6.0 or newer}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{'WaveActiveCountBits' has been marked as being introduced in HLSL ShaderModel 6.0 here, but the deployment target is HLSL ShaderModel 5.0}} + // expected-warning@#site {{'WaveActiveCountBits' is only available on Shader Model 6.0 or newer}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{'WaveActiveCountBits' has been marked as being introduced in Shader Model 6.0 here, but the deployment target is Shader Model 5.0}} // expected-note@#site {{enclose 'WaveActiveCountBits' in a __builtin_available check to silence this warning}} return hlsl::WaveActiveCountBits(b); // #site } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits