Skip to content

Commit 3f33c4c

Browse files
authored
[Clang][HLSL] Add environment parameter to availability attribute (#89809)
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. The environment parameter is currently supported only for HLSL. Fixes #89802
1 parent c34079c commit 3f33c4c

23 files changed

+508
-111
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,7 @@ def Availability : InheritableAttr {
999999
VersionArgument<"deprecated">, VersionArgument<"obsoleted">,
10001000
BoolArgument<"unavailable">, StringArgument<"message">,
10011001
BoolArgument<"strict">, StringArgument<"replacement">,
1002-
IntArgument<"priority">];
1002+
IntArgument<"priority">, IdentifierArgument<"environment">];
10031003
let AdditionalMembers =
10041004
[{static llvm::StringRef getPrettyPlatformName(llvm::StringRef Platform) {
10051005
return llvm::StringSwitch<llvm::StringRef>(Platform)
@@ -1019,7 +1019,7 @@ def Availability : InheritableAttr {
10191019
.Case("xros", "visionOS")
10201020
.Case("xros_app_extension", "visionOS (App Extension)")
10211021
.Case("swift", "Swift")
1022-
.Case("shadermodel", "HLSL ShaderModel")
1022+
.Case("shadermodel", "Shader Model")
10231023
.Case("ohos", "OpenHarmony OS")
10241024
.Default(llvm::StringRef());
10251025
}
@@ -1059,7 +1059,34 @@ static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) {
10591059
.Case("visionos_app_extension", "xros_app_extension")
10601060
.Case("ShaderModel", "shadermodel")
10611061
.Default(Platform);
1062-
} }];
1062+
}
1063+
static llvm::StringRef getPrettyEnviromentName(llvm::StringRef Environment) {
1064+
return llvm::StringSwitch<llvm::StringRef>(Environment)
1065+
.Case("pixel", "pixel shader")
1066+
.Case("vertex", "vertex shader")
1067+
.Case("geometry", "geometry shader")
1068+
.Case("hull", "hull shader")
1069+
.Case("domain", "domain shader")
1070+
.Case("compute", "compute shader")
1071+
.Case("mesh", "mesh shader")
1072+
.Case("amplification", "amplification shader")
1073+
.Case("library", "shader library")
1074+
.Default(Environment);
1075+
}
1076+
static llvm::Triple::EnvironmentType getEnvironmentType(llvm::StringRef Environment) {
1077+
return llvm::StringSwitch<llvm::Triple::EnvironmentType>(Environment)
1078+
.Case("pixel", llvm::Triple::Pixel)
1079+
.Case("vertex", llvm::Triple::Vertex)
1080+
.Case("geometry", llvm::Triple::Geometry)
1081+
.Case("hull", llvm::Triple::Hull)
1082+
.Case("domain", llvm::Triple::Domain)
1083+
.Case("compute", llvm::Triple::Compute)
1084+
.Case("mesh", llvm::Triple::Mesh)
1085+
.Case("amplification", llvm::Triple::Amplification)
1086+
.Case("library", llvm::Triple::Library)
1087+
.Default(llvm::Triple::UnknownEnvironment);
1088+
}
1089+
}];
10631090
let HasCustomParsing = 1;
10641091
let InheritEvenIfAlreadyPresent = 1;
10651092
let Subjects = SubjectList<[Named]>;

clang/include/clang/Basic/AttrDocs.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,6 +1593,11 @@ replacement=\ *string-literal*
15931593
a warning about use of a deprecated declaration. The Fix-It will replace
15941594
the deprecated declaration with the new declaration specified.
15951595

1596+
environment=\ *identifier*
1597+
Target environment in which this declaration is available. If present,
1598+
the availability attribute applies only to targets with the same platform
1599+
and environment. The parameter is currently supported only in HLSL.
1600+
15961601
Multiple availability attributes can be placed on a declaration, which may
15971602
correspond to different platforms. For most platforms, the availability
15981603
attribute with the platform corresponding to the target platform will be used;

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,8 @@ def err_zero_version : Error<
11121112
"version number must have non-zero major, minor, or sub-minor version">;
11131113
def err_availability_expected_platform : Error<
11141114
"expected a platform name, e.g., 'macos'">;
1115+
def err_availability_expected_environment : Error<
1116+
"expected an environment name, e.g., 'compute'">;
11151117

11161118
// objc_bridge_related attribute
11171119
def err_objcbridge_related_expected_related_class : Error<

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3837,6 +3837,9 @@ def note_cannot_use_trivial_abi_reason : Note<
38373837
// Availability attribute
38383838
def warn_availability_unknown_platform : Warning<
38393839
"unknown platform %0 in availability macro">, InGroup<Availability>;
3840+
def warn_availability_unknown_environment : Warning<
3841+
"unknown environment %0 in availability macro">, InGroup<Availability>;
3842+
38403843
def warn_availability_version_ordering : Warning<
38413844
"feature cannot be %select{introduced|deprecated|obsoleted}0 in %1 version "
38423845
"%2 before it was %select{introduced|deprecated|obsoleted}3 in version %4; "
@@ -3867,13 +3870,21 @@ def note_protocol_method : Note<
38673870
def warn_availability_fuchsia_unavailable_minor : Warning<
38683871
"Fuchsia API Level prohibits specifying a minor or sub-minor version">,
38693872
InGroup<Availability>;
3873+
def err_availability_unexpected_parameter: Error<
3874+
"unexpected parameter '%0' in availability attribute, not permitted in %select{HLSL|C/C++}1">;
38703875

38713876
def warn_unguarded_availability :
3872-
Warning<"%0 is only available on %1 %2 or newer">,
3877+
Warning<"%0 is only available %select{|in %4 environment }3on %1 %2 or newer">,
3878+
InGroup<UnguardedAvailability>, DefaultIgnore;
3879+
def warn_unguarded_availability_unavailable :
3880+
Warning<"%0 is unavailable">,
38733881
InGroup<UnguardedAvailability>, DefaultIgnore;
38743882
def warn_unguarded_availability_new :
38753883
Warning<warn_unguarded_availability.Summary>,
38763884
InGroup<UnguardedAvailabilityNew>;
3885+
def warn_unguarded_availability_unavailable_new :
3886+
Warning<warn_unguarded_availability_unavailable.Summary>,
3887+
InGroup<UnguardedAvailabilityNew>;
38773888
def note_decl_unguarded_availability_silence : Note<
38783889
"annotate %select{%1|anonymous %1}0 with an availability attribute to silence this warning">;
38793890
def note_unguarded_available_silence : Note<
@@ -5870,8 +5881,8 @@ def note_availability_specified_here : Note<
58705881
"%0 has been explicitly marked "
58715882
"%select{unavailable|deleted|deprecated}1 here">;
58725883
def note_partial_availability_specified_here : Note<
5873-
"%0 has been marked as being introduced in %1 %2 here, "
5874-
"but the deployment target is %1 %3">;
5884+
"%0 has been marked as being introduced in %1 %2 %select{|in %5 environment }4here, "
5885+
"but the deployment target is %1 %3%select{| %6 environment }4">;
58755886
def note_implicitly_deleted : Note<
58765887
"explicitly defaulted function was implicitly deleted here">;
58775888
def warn_not_enough_argument : Warning<

clang/include/clang/Parse/Parser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ class Parser : public CodeCompletionHandler {
153153
/// Identifier for "replacement".
154154
IdentifierInfo *Ident_replacement;
155155

156+
/// Identifier for "environment".
157+
IdentifierInfo *Ident_environment;
158+
156159
/// Identifiers used by the 'external_source_symbol' attribute.
157160
IdentifierInfo *Ident_language, *Ident_defined_in,
158161
*Ident_generated_declaration, *Ident_USR;

clang/include/clang/Sema/ParsedAttr.h

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class LangOptions;
4040
class Sema;
4141
class Stmt;
4242
class TargetInfo;
43+
struct IdentifierLoc;
4344

4445
/// Represents information about a change in availability for
4546
/// an entity, which is part of the encoding of the 'availability'
@@ -68,12 +69,14 @@ struct AvailabilityData {
6869
AvailabilityChange Changes[NumAvailabilitySlots];
6970
SourceLocation StrictLoc;
7071
const Expr *Replacement;
72+
const IdentifierLoc *EnvironmentLoc;
7173

7274
AvailabilityData(const AvailabilityChange &Introduced,
7375
const AvailabilityChange &Deprecated,
74-
const AvailabilityChange &Obsoleted,
75-
SourceLocation Strict, const Expr *ReplaceExpr)
76-
: StrictLoc(Strict), Replacement(ReplaceExpr) {
76+
const AvailabilityChange &Obsoleted, SourceLocation Strict,
77+
const Expr *ReplaceExpr, const IdentifierLoc *EnvironmentLoc)
78+
: StrictLoc(Strict), Replacement(ReplaceExpr),
79+
EnvironmentLoc(EnvironmentLoc) {
7780
Changes[IntroducedSlot] = Introduced;
7881
Changes[DeprecatedSlot] = Deprecated;
7982
Changes[ObsoletedSlot] = Obsoleted;
@@ -234,7 +237,7 @@ class ParsedAttr final
234237
const AvailabilityChange &deprecated,
235238
const AvailabilityChange &obsoleted, SourceLocation unavailable,
236239
const Expr *messageExpr, Form formUsed, SourceLocation strict,
237-
const Expr *replacementExpr)
240+
const Expr *replacementExpr, const IdentifierLoc *environmentLoc)
238241
: AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, formUsed),
239242
NumArgs(1), Invalid(false), UsedAsTypeAttr(false), IsAvailability(true),
240243
IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false),
@@ -243,8 +246,9 @@ class ParsedAttr final
243246
Info(ParsedAttrInfo::get(*this)) {
244247
ArgsUnion PVal(Parm);
245248
memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion));
246-
new (getAvailabilityData()) detail::AvailabilityData(
247-
introduced, deprecated, obsoleted, strict, replacementExpr);
249+
new (getAvailabilityData())
250+
detail::AvailabilityData(introduced, deprecated, obsoleted, strict,
251+
replacementExpr, environmentLoc);
248252
}
249253

250254
/// Constructor for objc_bridge_related attributes.
@@ -445,6 +449,12 @@ class ParsedAttr final
445449
return getAvailabilityData()->Replacement;
446450
}
447451

452+
const IdentifierLoc *getEnvironment() const {
453+
assert(getParsedKind() == AT_Availability &&
454+
"Not an availability attribute");
455+
return getAvailabilityData()->EnvironmentLoc;
456+
}
457+
448458
const ParsedType &getMatchingCType() const {
449459
assert(getParsedKind() == AT_TypeTagForDatatype &&
450460
"Not a type_tag_for_datatype attribute");
@@ -759,11 +769,13 @@ class AttributePool {
759769
const AvailabilityChange &obsoleted,
760770
SourceLocation unavailable, const Expr *MessageExpr,
761771
ParsedAttr::Form form, SourceLocation strict,
762-
const Expr *ReplacementExpr) {
772+
const Expr *ReplacementExpr,
773+
IdentifierLoc *EnvironmentLoc) {
763774
void *memory = allocate(AttributeFactory::AvailabilityAllocSize);
764-
return add(new (memory) ParsedAttr(
765-
attrName, attrRange, scopeName, scopeLoc, Param, introduced, deprecated,
766-
obsoleted, unavailable, MessageExpr, form, strict, ReplacementExpr));
775+
return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc,
776+
Param, introduced, deprecated, obsoleted,
777+
unavailable, MessageExpr, form, strict,
778+
ReplacementExpr, EnvironmentLoc));
767779
}
768780

769781
ParsedAttr *create(IdentifierInfo *attrName, SourceRange attrRange,
@@ -994,10 +1006,12 @@ class ParsedAttributes : public ParsedAttributesView {
9941006
const AvailabilityChange &obsoleted,
9951007
SourceLocation unavailable, const Expr *MessageExpr,
9961008
ParsedAttr::Form form, SourceLocation strict,
997-
const Expr *ReplacementExpr) {
998-
ParsedAttr *attr = pool.create(
999-
attrName, attrRange, scopeName, scopeLoc, Param, introduced, deprecated,
1000-
obsoleted, unavailable, MessageExpr, form, strict, ReplacementExpr);
1009+
const Expr *ReplacementExpr,
1010+
IdentifierLoc *EnvironmentLoc) {
1011+
ParsedAttr *attr =
1012+
pool.create(attrName, attrRange, scopeName, scopeLoc, Param, introduced,
1013+
deprecated, obsoleted, unavailable, MessageExpr, form,
1014+
strict, ReplacementExpr, EnvironmentLoc);
10011015
addAtEnd(attr);
10021016
return attr;
10031017
}

clang/include/clang/Sema/Sema.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "clang/Basic/Cuda.h"
4040
#include "clang/Basic/DarwinSDKInfo.h"
4141
#include "clang/Basic/ExpressionTraits.h"
42+
#include "clang/Basic/IdentifierTable.h"
4243
#include "clang/Basic/Module.h"
4344
#include "clang/Basic/OpenCLOptions.h"
4445
#include "clang/Basic/PragmaKinds.h"
@@ -3580,13 +3581,13 @@ class Sema final : public SemaBase {
35803581
bool CheckAttrTarget(const ParsedAttr &CurrAttr);
35813582
bool CheckAttrNoArgs(const ParsedAttr &CurrAttr);
35823583

3583-
AvailabilityAttr *
3584-
mergeAvailabilityAttr(NamedDecl *D, const AttributeCommonInfo &CI,
3585-
IdentifierInfo *Platform, bool Implicit,
3586-
VersionTuple Introduced, VersionTuple Deprecated,
3587-
VersionTuple Obsoleted, bool IsUnavailable,
3588-
StringRef Message, bool IsStrict, StringRef Replacement,
3589-
AvailabilityMergeKind AMK, int Priority);
3584+
AvailabilityAttr *mergeAvailabilityAttr(
3585+
NamedDecl *D, const AttributeCommonInfo &CI, IdentifierInfo *Platform,
3586+
bool Implicit, VersionTuple Introduced, VersionTuple Deprecated,
3587+
VersionTuple Obsoleted, bool IsUnavailable, StringRef Message,
3588+
bool IsStrict, StringRef Replacement, AvailabilityMergeKind AMK,
3589+
int Priority, IdentifierInfo *IIEnvironment);
3590+
35903591
TypeVisibilityAttr *
35913592
mergeTypeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI,
35923593
TypeVisibilityAttr::VisibilityType Vis);

clang/lib/AST/DeclBase.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -666,12 +666,28 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
666666
// Make sure that this declaration has already been introduced.
667667
if (!A->getIntroduced().empty() &&
668668
EnclosingVersion < A->getIntroduced()) {
669-
if (Message) {
670-
Message->clear();
671-
llvm::raw_string_ostream Out(*Message);
672-
VersionTuple VTI(A->getIntroduced());
673-
Out << "introduced in " << PrettyPlatformName << ' '
674-
<< VTI << HintMessage;
669+
IdentifierInfo *IIEnv = A->getEnvironment();
670+
StringRef TargetEnv =
671+
Context.getTargetInfo().getTriple().getEnvironmentName();
672+
StringRef EnvName = AvailabilityAttr::getPrettyEnviromentName(TargetEnv);
673+
// Matching environment or no environment on attribute
674+
if (!IIEnv || (!TargetEnv.empty() && IIEnv->getName() == TargetEnv)) {
675+
if (Message) {
676+
Message->clear();
677+
llvm::raw_string_ostream Out(*Message);
678+
VersionTuple VTI(A->getIntroduced());
679+
Out << "introduced in " << PrettyPlatformName << " " << VTI << " "
680+
<< EnvName << HintMessage;
681+
}
682+
}
683+
// Non-matching environment or no environment on target
684+
else {
685+
if (Message) {
686+
Message->clear();
687+
llvm::raw_string_ostream Out(*Message);
688+
Out << "not available on " << PrettyPlatformName << " " << EnvName
689+
<< HintMessage;
690+
}
675691
}
676692

677693
return A->getStrict() ? AR_Unavailable : AR_NotYetIntroduced;

clang/lib/Headers/hlsl/hlsl_intrinsics.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,21 @@ namespace hlsl {
1818

1919
#define _HLSL_BUILTIN_ALIAS(builtin) \
2020
__attribute__((clang_builtin_alias(builtin)))
21-
#define _HLSL_AVAILABILITY(environment, version) \
22-
__attribute__((availability(environment, introduced = version)))
21+
#define _HLSL_AVAILABILITY(platform, version) \
22+
__attribute__((availability(platform, introduced = version)))
23+
#define _HLSL_AVAILABILITY_STAGE(platform, version, stage) \
24+
__attribute__(( \
25+
availability(platform, introduced = version, environment = stage)))
2326

2427
#ifdef __HLSL_ENABLE_16_BIT
25-
#define _HLSL_16BIT_AVAILABILITY(environment, version) \
26-
__attribute__((availability(environment, introduced = version)))
28+
#define _HLSL_16BIT_AVAILABILITY(platform, version) \
29+
__attribute__((availability(platform, introduced = version)))
30+
#define _HLSL_16BIT_AVAILABILITY_STAGE(platform, version, stage) \
31+
__attribute__(( \
32+
availability(platform, introduced = version, environment = stage)))
2733
#else
2834
#define _HLSL_16BIT_AVAILABILITY(environment, version)
35+
#define _HLSL_16BIT_AVAILABILITY_STAGE(environment, version, stage)
2936
#endif
3037

3138
//===----------------------------------------------------------------------===//

clang/lib/Index/CommentToXML.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "clang/AST/Comment.h"
1313
#include "clang/AST/CommentVisitor.h"
1414
#include "clang/Basic/FileManager.h"
15+
#include "clang/Basic/IdentifierTable.h"
1516
#include "clang/Basic/SourceManager.h"
1617
#include "clang/Format/Format.h"
1718
#include "clang/Index/USRGeneration.h"
@@ -1052,6 +1053,11 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
10521053
}
10531054
if (AA->getUnavailable())
10541055
Result << "<Unavailable/>";
1056+
1057+
IdentifierInfo *Environment = AA->getEnvironment();
1058+
if (Environment) {
1059+
Result << "<Environment>" << Environment->getName() << "</Environment>";
1060+
}
10551061
Result << "</Availability>";
10561062
}
10571063
}

clang/lib/Parse/ParseDecl.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1256,6 +1256,7 @@ void Parser::ParseAvailabilityAttribute(
12561256
enum { Introduced, Deprecated, Obsoleted, Unknown };
12571257
AvailabilityChange Changes[Unknown];
12581258
ExprResult MessageExpr, ReplacementExpr;
1259+
IdentifierLoc *EnvironmentLoc = nullptr;
12591260

12601261
// Opening '('.
12611262
BalancedDelimiterTracker T(*this, tok::l_paren);
@@ -1303,6 +1304,7 @@ void Parser::ParseAvailabilityAttribute(
13031304
Ident_message = PP.getIdentifierInfo("message");
13041305
Ident_strict = PP.getIdentifierInfo("strict");
13051306
Ident_replacement = PP.getIdentifierInfo("replacement");
1307+
Ident_environment = PP.getIdentifierInfo("environment");
13061308
}
13071309

13081310
// Parse the optional "strict", the optional "replacement" and the set of
@@ -1350,6 +1352,13 @@ void Parser::ParseAvailabilityAttribute(
13501352
continue;
13511353
}
13521354

1355+
if (Keyword == Ident_environment) {
1356+
if (EnvironmentLoc != nullptr) {
1357+
Diag(KeywordLoc, diag::err_availability_redundant)
1358+
<< Keyword << SourceRange(EnvironmentLoc->Loc);
1359+
}
1360+
}
1361+
13531362
if (Tok.isNot(tok::equal)) {
13541363
Diag(Tok, diag::err_expected_after) << Keyword << tok::equal;
13551364
SkipUntil(tok::r_paren, StopAtSemi);
@@ -1371,6 +1380,15 @@ void Parser::ParseAvailabilityAttribute(
13711380
continue;
13721381
}
13731382
}
1383+
if (Keyword == Ident_environment) {
1384+
if (Tok.isNot(tok::identifier)) {
1385+
Diag(Tok, diag::err_availability_expected_environment);
1386+
SkipUntil(tok::r_paren, StopAtSemi);
1387+
return;
1388+
}
1389+
EnvironmentLoc = ParseIdentifierLoc();
1390+
continue;
1391+
}
13741392

13751393
// Special handling of 'NA' only when applied to introduced or
13761394
// deprecated.
@@ -1452,7 +1470,7 @@ void Parser::ParseAvailabilityAttribute(
14521470
SourceRange(AvailabilityLoc, T.getCloseLocation()), ScopeName,
14531471
ScopeLoc, Platform, Changes[Introduced], Changes[Deprecated],
14541472
Changes[Obsoleted], UnavailableLoc, MessageExpr.get(), Form,
1455-
StrictLoc, ReplacementExpr.get());
1473+
StrictLoc, ReplacementExpr.get(), EnvironmentLoc);
14561474
}
14571475

14581476
/// Parse the contents of the "external_source_symbol" attribute.

clang/lib/Sema/SemaAPINotes.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,8 @@ static void ProcessAPINotes(Sema &S, Decl *D,
269269
ASTAllocateString(S.Context, Info.UnavailableMsg),
270270
/*Strict=*/false,
271271
/*Replacement=*/StringRef(),
272-
/*Priority=*/Sema::AP_Explicit);
272+
/*Priority=*/Sema::AP_Explicit,
273+
/*Environment=*/nullptr);
273274
},
274275
[](const Decl *D) {
275276
return llvm::find_if(D->attrs(), [](const Attr *next) -> bool {

0 commit comments

Comments
 (0)