Skip to content

Commit

Permalink
[HLSL] Adjust access specifier behavior
Browse files Browse the repository at this point in the history
HLSL doesn't support access specifiers. This change has two components:

1) Make default access for classes public
2) Diagnose the use of access specifiers as a clang HLSL extension

As long as the default behavior for access specifiers matches HLSL,
allowing them to be used doesn't cause sourece incompatability with
valid code. As such enabling them as a clang extension seems like a
reasonable approach.

Fixes llvm#55124

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D124487
  • Loading branch information
llvm-beanz committed Apr 28, 2022
1 parent bd30d4b commit 0d6b574
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 2 deletions.
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -1362,3 +1362,6 @@ def PedanticMacros : DiagGroup<"pedantic-macros",

def BranchProtection : DiagGroup<"branch-protection">;

// HLSL diagnostic groups
// Warnings for HLSL Clang extensions
def HLSLExtension : DiagGroup<"hlsl-extensions">;
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1599,5 +1599,8 @@ def note_max_tokens_total_override : Note<"total token limit set here">;
def err_expected_semantic_identifier : Error<
"expected HLSL Semantic identifier">;
def err_unknown_hlsl_semantic : Error<"unknown HLSL semantic %0">;
def ext_hlsl_access_specifiers : ExtWarn<
"access specifiers are a clang HLSL extension">,
InGroup<HLSLExtension>;

} // end of Parser diagnostics
10 changes: 8 additions & 2 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2170,8 +2170,11 @@ BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {

// Parse an (optional) access specifier.
AccessSpecifier Access = getAccessSpecifierIfPresent();
if (Access != AS_none)
if (Access != AS_none) {
ConsumeToken();
if (getLangOpts().HLSL)
Diag(Tok.getLocation(), diag::ext_hlsl_access_specifiers);
}

CheckMisplacedCXX11Attribute(Attributes, StartLoc);

Expand Down Expand Up @@ -3270,6 +3273,8 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas(
LLVM_FALLTHROUGH;
case tok::kw_public:
case tok::kw_protected: {
if (getLangOpts().HLSL)
Diag(Tok.getLocation(), diag::ext_hlsl_access_specifiers);
AccessSpecifier NewAS = getAccessSpecifierIfPresent();
assert(NewAS != AS_none);
// Current token is a C++ access specifier.
Expand Down Expand Up @@ -3509,8 +3514,9 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// C++ 11p3: Members of a class defined with the keyword class are private
// by default. Members of a class defined with the keywords struct or union
// are public by default.
// HLSL: In HLSL members of a class are public by default.
AccessSpecifier CurAS;
if (TagType == DeclSpec::TST_class)
if (TagType == DeclSpec::TST_class && !getLangOpts().HLSL)
CurAS = AS_private;
else
CurAS = AS_public;
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2501,6 +2501,11 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
bool Virtual, AccessSpecifier Access,
TypeSourceInfo *TInfo,
SourceLocation EllipsisLoc) {
// In HLSL, unspecified class access is public rather than private.
if (getLangOpts().HLSL && Class->getTagKind() == TTK_Class &&
Access == AS_none)
Access = AS_public;

QualType BaseType = TInfo->getType();
if (BaseType->containsErrors()) {
// Already emitted a diagnostic when parsing the error type.
Expand Down
55 changes: 55 additions & 0 deletions clang/test/ParserHLSL/access_specifiers.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s -verify
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -DSTRUCT -o - %s -verify

#ifdef STRUCT
#define KEYWORD struct
#else
#define KEYWORD class
#endif

KEYWORD Doggo {
int legs; // expected-note {{member is declared here}} expected-note {{member is declared here}}
protected: // expected-warning {{access specifiers are a clang HLSL extension}}
int ears[2]; // expected-note {{declared protected here}}
private: // expected-warning {{access specifiers are a clang HLSL extension}}
int tail; // expected-note {{declared private here}} expected-note {{declared private here}}
};

KEYWORD Shiba : public Doggo { // expected-warning {{access specifiers are a clang HLSL extension}}
int undercoat;
};

KEYWORD Akita : Doggo {
int floof;
};

KEYWORD Chow : private Doggo { // expected-warning {{access specifiers are a clang HLSL extension}} expected-note {{constrained by private inheritance here}}
int megafloof;
};

KEYWORD Dachshund : protected Doggo { // expected-warning {{access specifiers are a clang HLSL extension}} expected-note {{constrained by protected inheritance here}}
int wiry;
};

void Puppers() {
Shiba Shibe;
Shibe.undercoat = 0xFFFF;
Shibe.legs = 4;

Shibe.tail = 1; // expected-error {{'tail' is a private member of 'Doggo'}}
Shibe.ears[0] = 1; // expected-error {{'ears' is a protected member of 'Doggo'}}

Akita Aki;
Aki.floof = 0xFFFF;
Aki.legs = 4;

Aki.tail = 1; // expected-error {{'tail' is a private member of 'Doggo'}}

Chow Ch;
Ch.megafloof = 0xFFFF;

Ch.legs = 4; // expected-error {{'legs' is a private member of 'Doggo'}}

Dachshund DH;
DH.legs = 4; // expected-error {{'legs' is a protected member of 'Doggo'}}
}

0 comments on commit 0d6b574

Please sign in to comment.