Skip to content

Commit 5f43ed8

Browse files
committed
Add lexing of integer literals
- Integrate the use of the `NumericLiteralParser` to lex integer literals - Add additional hlsl specific diagnostics messages
1 parent 98deff6 commit 5f43ed8

File tree

5 files changed

+139
-0
lines changed

5 files changed

+139
-0
lines changed

clang/include/clang/Basic/DiagnosticLexKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,10 @@ Error<"expected 'begin' or 'end'">;
10201020

10211021
// HLSL Root Signature Lexing Errors
10221022
let CategoryName = "Root Signature Lexical Issue" in {
1023+
def err_hlsl_invalid_number_literal:
1024+
Error<"expected number literal is not a supported number literal of unsigned integer or integer">;
1025+
def err_hlsl_number_literal_overflow :
1026+
Error<"provided %select{unsigned integer|signed integer}0 literal '%1' that overflows the maximum of 32 bits">;
10231027
def err_hlsl_invalid_token: Error<"unable to lex a valid Root Signature token">;
10241028
}
10251029

clang/include/clang/Parse/HLSLRootSignatureTokenKinds.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
// General Tokens:
2525
TOK(invalid)
26+
TOK(int_literal)
2627

2728
// Punctuators:
2829
PUNCTUATOR(l_paren, '(')

clang/include/clang/Parse/ParseHLSLRootSignature.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
#ifndef LLVM_CLANG_PARSE_PARSEHLSLROOTSIGNATURE_H
1414
#define LLVM_CLANG_PARSE_PARSEHLSLROOTSIGNATURE_H
1515

16+
#include "clang/AST/APValue.h"
1617
#include "clang/Basic/DiagnosticLex.h"
18+
#include "clang/Lex/LiteralSupport.h"
1719
#include "clang/Lex/Preprocessor.h"
1820

1921
#include "llvm/ADT/SmallVector.h"
@@ -33,6 +35,8 @@ struct RootSignatureToken {
3335
// Retain the SouceLocation of the token for diagnostics
3436
clang::SourceLocation TokLoc;
3537

38+
APValue NumLiteral = APValue();
39+
3640
// Constructors
3741
RootSignatureToken(clang::SourceLocation TokLoc) : TokLoc(TokLoc) {}
3842
};
@@ -60,6 +64,8 @@ class RootSignatureLexer {
6064
clang::SourceLocation SourceLoc;
6165
clang::Preprocessor &PP;
6266

67+
bool LexNumber(RootSignatureToken &Result);
68+
6369
// Consumes the internal buffer for a single token.
6470
//
6571
// The return value denotes if there was a failure.

clang/lib/Parse/ParseHLSLRootSignature.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,61 @@ namespace hlsl {
55

66
// Lexer Definitions
77

8+
static bool IsNumberChar(char C) {
9+
// TODO(#120472): extend for float support exponents
10+
return isdigit(C); // integer support
11+
}
12+
13+
bool RootSignatureLexer::LexNumber(RootSignatureToken &Result) {
14+
// NumericLiteralParser does not handle the sign so we will manually apply it
15+
bool Negative = Buffer.front() == '-';
16+
bool Signed = Negative || Buffer.front() == '+';
17+
if (Signed)
18+
AdvanceBuffer();
19+
20+
// Retrieve the possible number
21+
StringRef NumSpelling = Buffer.take_while(IsNumberChar);
22+
23+
// Catch this now as the Literal Parser will accept it as valid
24+
if (NumSpelling.empty()) {
25+
PP.getDiagnostics().Report(Result.TokLoc,
26+
diag::err_hlsl_invalid_number_literal);
27+
return true;
28+
}
29+
30+
// Parse the numeric value and do semantic checks on its specification
31+
clang::NumericLiteralParser Literal(NumSpelling, SourceLoc,
32+
PP.getSourceManager(), PP.getLangOpts(),
33+
PP.getTargetInfo(), PP.getDiagnostics());
34+
if (Literal.hadError)
35+
return true; // Error has already been reported so just return
36+
37+
if (!Literal.isIntegerLiteral()) {
38+
// Note: if IsNumberChar allows for hexidecimal we will need to turn this
39+
// into a diagnostics for potential fixed-point literals
40+
llvm_unreachable("IsNumberChar will only support digits");
41+
return true;
42+
}
43+
44+
// Retrieve the number value to store into the token
45+
Result.Kind = TokenKind::int_literal;
46+
47+
llvm::APSInt X = llvm::APSInt(32, !Signed);
48+
if (Literal.GetIntegerValue(X)) {
49+
// Report that the value has overflowed
50+
PP.getDiagnostics().Report(Result.TokLoc,
51+
diag::err_hlsl_number_literal_overflow)
52+
<< (unsigned)Signed << NumSpelling;
53+
return true;
54+
}
55+
56+
X = Negative ? -X : X;
57+
Result.NumLiteral = APValue(X);
58+
59+
AdvanceBuffer(NumSpelling.size());
60+
return false;
61+
}
62+
863
bool RootSignatureLexer::Lex(SmallVector<RootSignatureToken> &Tokens) {
964
// Discard any leading whitespace
1065
AdvanceBuffer(Buffer.take_while(isspace).size());
@@ -41,6 +96,10 @@ bool RootSignatureLexer::LexToken(RootSignatureToken &Result) {
4196
break;
4297
}
4398

99+
// Numeric constant
100+
if (isdigit(C) || C == '-' || C == '+')
101+
return LexNumber(Result);
102+
44103
// Unable to match on any token type
45104
PP.getDiagnostics().Report(Result.TokLoc, diag::err_hlsl_invalid_token);
46105
return true;

clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,39 @@ class ParseHLSLRootSignatureTest : public ::testing::Test {
111111

112112
// Valid Lexing Tests
113113

114+
TEST_F(ParseHLSLRootSignatureTest, ValidLexNumbersTest) {
115+
// This test will check that we can lex different number tokens
116+
const llvm::StringLiteral Source = R"cc(
117+
-42 42 +42
118+
)cc";
119+
120+
TrivialModuleLoader ModLoader;
121+
auto PP = CreatePP(Source, ModLoader);
122+
auto TokLoc = SourceLocation();
123+
124+
// Test no diagnostics produced
125+
Consumer->SetNoDiag();
126+
127+
hlsl::RootSignatureLexer Lexer(Source, TokLoc, *PP);
128+
129+
SmallVector<hlsl::RootSignatureToken> Tokens;
130+
ASSERT_FALSE(Lexer.Lex(Tokens));
131+
ASSERT_TRUE(Consumer->IsSatisfied());
132+
133+
SmallVector<hlsl::TokenKind> Expected = {
134+
hlsl::TokenKind::int_literal,
135+
hlsl::TokenKind::int_literal,
136+
hlsl::TokenKind::int_literal,
137+
};
138+
CheckTokens(Tokens, Expected);
139+
}
140+
114141
TEST_F(ParseHLSLRootSignatureTest, ValidLexAllTokensTest) {
115142
// This test will check that we can lex all defined tokens as defined in
116143
// HLSLRootSignatureTokenKinds.def, plus some additional integer variations
117144
const llvm::StringLiteral Source = R"cc(
145+
42
146+
118147
(),|=
119148
)cc";
120149

@@ -144,6 +173,46 @@ TEST_F(ParseHLSLRootSignatureTest, ValidLexAllTokensTest) {
144173

145174
// Invalid Lexing Tests
146175

176+
TEST_F(ParseHLSLRootSignatureTest, InvalidLexOverflowedNumberTest) {
177+
// This test will check that the lexing fails due to an integer overflow
178+
const llvm::StringLiteral Source = R"cc(
179+
4294967296
180+
)cc";
181+
182+
TrivialModuleLoader ModLoader;
183+
auto PP = CreatePP(Source, ModLoader);
184+
auto TokLoc = SourceLocation();
185+
186+
// Test correct diagnostic produced
187+
Consumer->SetExpected(diag::err_hlsl_number_literal_overflow);
188+
189+
hlsl::RootSignatureLexer Lexer(Source, TokLoc, *PP);
190+
191+
SmallVector<hlsl::RootSignatureToken> Tokens;
192+
ASSERT_TRUE(Lexer.Lex(Tokens));
193+
ASSERT_TRUE(Consumer->IsSatisfied());
194+
}
195+
196+
TEST_F(ParseHLSLRootSignatureTest, InvalidLexEmptyNumberTest) {
197+
// This test will check that the lexing fails due to no integer being provided
198+
const llvm::StringLiteral Source = R"cc(
199+
-
200+
)cc";
201+
202+
TrivialModuleLoader ModLoader;
203+
auto PP = CreatePP(Source, ModLoader);
204+
auto TokLoc = SourceLocation();
205+
206+
// Test correct diagnostic produced
207+
Consumer->SetExpected(diag::err_hlsl_invalid_number_literal);
208+
209+
hlsl::RootSignatureLexer Lexer(Source, TokLoc, *PP);
210+
211+
SmallVector<hlsl::RootSignatureToken> Tokens;
212+
ASSERT_TRUE(Lexer.Lex(Tokens));
213+
ASSERT_TRUE(Consumer->IsSatisfied());
214+
}
215+
147216
TEST_F(ParseHLSLRootSignatureTest, InvalidLexIdentifierTest) {
148217
// This test will check that the lexing fails due to no valid token
149218
const llvm::StringLiteral Source = R"cc(

0 commit comments

Comments
 (0)