Skip to content

Commit ca854e2

Browse files
committed
improve diagnostics for root elements
1 parent 25152be commit ca854e2

File tree

4 files changed

+53
-23
lines changed

4 files changed

+53
-23
lines changed

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1857,6 +1857,7 @@ def err_hlsl_virtual_inheritance
18571857
: Error<"virtual inheritance is unsupported in HLSL">;
18581858

18591859
// HLSL Root Signature Parser Diagnostics
1860+
def err_hlsl_rootsig_invalid_param : Error<"invalid parameter of %0">;
18601861
def err_hlsl_rootsig_repeat_param : Error<"specified the same parameter '%0' multiple times">;
18611862
def err_hlsl_rootsig_missing_param : Error<"did not specify mandatory parameter '%0'">;
18621863
def err_hlsl_number_literal_overflow : Error<

clang/lib/Parse/ParseHLSLRootSignature.cpp

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,54 +25,60 @@ RootSignatureParser::RootSignatureParser(
2525
Lexer(Signature->getString()), PP(PP), CurToken(0) {}
2626

2727
bool RootSignatureParser::parse() {
28-
// Iterate as many RootSignatureElements as possible
29-
do {
28+
// Iterate as many RootSignatureElements as possible, until we hit the
29+
// end of the stream
30+
while (!peekExpectedToken(TokenKind::end_of_stream)) {
3031
std::optional<RootSignatureElement> Element = std::nullopt;
3132
if (tryConsumeExpectedToken(TokenKind::kw_RootFlags)) {
33+
// RootFlags
3234
SourceLocation ElementLoc = getTokenLocation(CurToken);
3335
auto Flags = parseRootFlags();
3436
if (!Flags.has_value())
3537
return true;
3638
Element = RootSignatureElement(ElementLoc, *Flags);
37-
}
38-
39-
if (tryConsumeExpectedToken(TokenKind::kw_RootConstants)) {
39+
} else if (tryConsumeExpectedToken(TokenKind::kw_RootConstants)) {
40+
// RootConstants
4041
SourceLocation ElementLoc = getTokenLocation(CurToken);
4142
auto Constants = parseRootConstants();
4243
if (!Constants.has_value())
4344
return true;
4445
Element = RootSignatureElement(ElementLoc, *Constants);
45-
}
46-
47-
if (tryConsumeExpectedToken(TokenKind::kw_DescriptorTable)) {
46+
} else if (tryConsumeExpectedToken(TokenKind::kw_DescriptorTable)) {
47+
// DescriptorTable
4848
SourceLocation ElementLoc = getTokenLocation(CurToken);
4949
auto Table = parseDescriptorTable();
5050
if (!Table.has_value())
5151
return true;
5252
Element = RootSignatureElement(ElementLoc, *Table);
53-
}
54-
55-
if (tryConsumeExpectedToken(
56-
{TokenKind::kw_CBV, TokenKind::kw_SRV, TokenKind::kw_UAV})) {
53+
} else if (tryConsumeExpectedToken(
54+
{TokenKind::kw_CBV, TokenKind::kw_SRV, TokenKind::kw_UAV})) {
55+
// RootDescriptor - CBV, SRV, UAV
5756
SourceLocation ElementLoc = getTokenLocation(CurToken);
5857
auto Descriptor = parseRootDescriptor();
5958
if (!Descriptor.has_value())
6059
return true;
6160
Element = RootSignatureElement(ElementLoc, *Descriptor);
62-
}
63-
64-
if (tryConsumeExpectedToken(TokenKind::kw_StaticSampler)) {
61+
} else if (tryConsumeExpectedToken(TokenKind::kw_StaticSampler)) {
62+
// StaticSampler
6563
SourceLocation ElementLoc = getTokenLocation(CurToken);
6664
auto Sampler = parseStaticSampler();
6765
if (!Sampler.has_value())
6866
return true;
6967
Element = RootSignatureElement(ElementLoc, *Sampler);
68+
} else {
69+
consumeNextToken(); // position to start of invalid token
70+
reportDiag(diag::err_hlsl_rootsig_invalid_param)
71+
<< /*param of=*/TokenKind::kw_RootSignature;
72+
return true;
7073
}
7174

7275
if (Element.has_value())
7376
Elements.push_back(*Element);
7477

75-
} while (tryConsumeExpectedToken(TokenKind::pu_comma));
78+
// ',' denotes another element, otherwise, expected to be at end of stream
79+
if (!tryConsumeExpectedToken(TokenKind::pu_comma))
80+
break;
81+
}
7682

7783
return consumeExpectedToken(TokenKind::end_of_stream);
7884
}
@@ -251,9 +257,7 @@ std::optional<DescriptorTable> RootSignatureParser::parseDescriptorTable() {
251257
return std::nullopt;
252258
Elements.push_back(RootSignatureElement(ElementLoc, *Clause));
253259
Table.NumClauses++;
254-
}
255-
256-
if (tryConsumeExpectedToken(TokenKind::kw_visibility)) {
260+
} else if (tryConsumeExpectedToken(TokenKind::kw_visibility)) {
257261
if (Visibility.has_value()) {
258262
reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
259263
return std::nullopt;

clang/test/SemaHLSL/RootSignature-err.hlsl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ void bad_root_signature_2() {}
1717
[RootSignature(""), RootSignature("")] // expected-warning {{attribute 'RootSignature' is already applied}}
1818
void bad_root_signature_3() {}
1919

20-
[RootSignature("DescriptorTable(), invalid")] // expected-error {{expected end of stream}}
20+
[RootSignature("DescriptorTable(), invalid")] // expected-error {{invalid parameter of RootSignature}}
2121
void bad_root_signature_4() {}
2222

23-
// expected-error@+1 {{expected ')'}}
24-
[RootSignature("RootConstants(b0, num32BitConstants = 1, invalid)")]
23+
// expected-error@+1 {{expected end of stream}}
24+
[RootSignature("RootFlags() RootConstants(b0, num32BitConstants = 1))")]
2525
void bad_root_signature_5() {}
2626

2727
#define MultiLineRootSignature \

clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidParseInvalidTokenTest) {
865865
Signature, *PP);
866866

867867
// Test correct diagnostic produced - invalid token
868-
Consumer->setExpected(diag::err_expected);
868+
Consumer->setExpected(diag::err_hlsl_rootsig_invalid_param);
869869
ASSERT_TRUE(Parser.parse());
870870

871871
ASSERT_TRUE(Consumer->isSatisfied());
@@ -1239,4 +1239,29 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidNonZeroFlagsTest) {
12391239
ASSERT_TRUE(Consumer->isSatisfied());
12401240
}
12411241

1242+
TEST_F(ParseHLSLRootSignatureTest, InvalidRootElementMissingCommaTest) {
1243+
// This test will check that an error is produced when there is a missing
1244+
// comma between parameters
1245+
const llvm::StringLiteral Source = R"cc(
1246+
RootFlags()
1247+
RootConstants(num32BitConstants = 1, b0)
1248+
)cc";
1249+
1250+
auto Ctx = createMinimalASTContext();
1251+
StringLiteral *Signature = wrapSource(Ctx, Source);
1252+
1253+
TrivialModuleLoader ModLoader;
1254+
auto PP = createPP(Source, ModLoader);
1255+
1256+
SmallVector<RootSignatureElement> Elements;
1257+
hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements,
1258+
Signature, *PP);
1259+
1260+
// Test correct diagnostic produced
1261+
Consumer->setExpected(diag::err_expected);
1262+
ASSERT_TRUE(Parser.parse());
1263+
1264+
ASSERT_TRUE(Consumer->isSatisfied());
1265+
}
1266+
12421267
} // anonymous namespace

0 commit comments

Comments
 (0)