diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1599,5 +1599,7 @@ 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">; } // end of Parser diagnostics diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -2170,8 +2170,11 @@ // 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); @@ -3270,6 +3273,8 @@ 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. @@ -3509,8 +3514,9 @@ // 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; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2501,6 +2501,11 @@ 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. diff --git a/clang/test/ParserHLSL/access_specifiers.hlsl b/clang/test/ParserHLSL/access_specifiers.hlsl new file mode 100644 --- /dev/null +++ b/clang/test/ParserHLSL/access_specifiers.hlsl @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s -verify + +class Doggo { + // expected-note@+1 {{member is declared here}} + int legs; +// expected-warning@+1 {{access specifiers are a clang HLSL extension}} +private: + // expected-note@+2 {{declared private here}} + // expected-note@+1 {{declared private here}} + int tail; +}; + +// expected-warning@+1 {{access specifiers are a clang HLSL extension}} +class Shiba : public Doggo { + int undercoat; +}; + +class Akita : Doggo { + int floof; +}; + +// expected-note@+2 {{constrained by private inheritance here}} +// expected-warning@+1 {{access specifiers are a clang HLSL extension}} +class Chow : private Doggo { + int megafloof; +}; + +void main() { + Shiba Shibe; + Shibe.undercoat = 0xFFFF; + Shibe.legs = 4; + + // expected-error@+1 {{'tail' is a private member of 'Doggo'}} + Shibe.tail = 1; + + Akita Aki; + Aki.floof = 0xFFFF; + Aki.legs = 4; + + // expected-error@+1 {{'tail' is a private member of 'Doggo'}} + Aki.tail = 1; + + Chow Ch; + Ch.megafloof = 0xFFFF; + + // expected-error@+1 {{'legs' is a private member of 'Doggo'}} + Ch.legs = 4; +}