summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorDarren Wihandi <65404740+fairywreath@users.noreply.github.com>2024-12-03 16:40:09 -0500
committerGitHub <noreply@github.com>2024-12-03 13:40:09 -0800
commit98cab6fa86c9e594fb69571cf1d864294b0aae45 (patch)
tree37528d00b3d280c6ea68f26657aafa539c7b5636 /source
parent600cce28606ba36b31756bf0422d892d0e242b63 (diff)
Conform non-suffixed integer literals (#5717)
* Make non-suffixed integer literal type resolution conform to C * Update integer literal tests * Clean up integer literal implementation a bit * Update docs on integer literals * Clean up docs update * Clean up docs update * Add comment on INT64_MIN edge case * Fixed failing test, fixed formatting and cleaned up code --------- Co-authored-by: Yong He <yonghe@outlook.com>
Diffstat (limited to 'source')
-rw-r--r--source/compiler-core/slang-lexer.cpp10
-rw-r--r--source/compiler-core/slang-lexer.h5
-rw-r--r--source/slang/slang-diagnostic-defs.h6
-rw-r--r--source/slang/slang-parser.cpp83
4 files changed, 92 insertions, 12 deletions
diff --git a/source/compiler-core/slang-lexer.cpp b/source/compiler-core/slang-lexer.cpp
index bf109e7fb..84a4df93b 100644
--- a/source/compiler-core/slang-lexer.cpp
+++ b/source/compiler-core/slang-lexer.cpp
@@ -673,7 +673,10 @@ static int _readOptionalBase(char const** ioCursor)
}
-IntegerLiteralValue getIntegerLiteralValue(Token const& token, UnownedStringSlice* outSuffix)
+IntegerLiteralValue getIntegerLiteralValue(
+ Token const& token,
+ UnownedStringSlice* outSuffix,
+ bool* outIsDecimalBase)
{
IntegerLiteralValue value = 0;
@@ -698,6 +701,11 @@ IntegerLiteralValue getIntegerLiteralValue(Token const& token, UnownedStringSlic
*outSuffix = UnownedStringSlice(cursor, end);
}
+ if (outIsDecimalBase)
+ {
+ *outIsDecimalBase = (base == 10);
+ }
+
return value;
}
diff --git a/source/compiler-core/slang-lexer.h b/source/compiler-core/slang-lexer.h
index a9883ced6..a36719ab7 100644
--- a/source/compiler-core/slang-lexer.h
+++ b/source/compiler-core/slang-lexer.h
@@ -172,7 +172,10 @@ String getFileNameTokenValue(Token const& token);
typedef int64_t IntegerLiteralValue;
typedef double FloatingPointLiteralValue;
-IntegerLiteralValue getIntegerLiteralValue(Token const& token, UnownedStringSlice* outSuffix = 0);
+IntegerLiteralValue getIntegerLiteralValue(
+ Token const& token,
+ UnownedStringSlice* outSuffix = 0,
+ bool* outIsDecimalBase = 0);
FloatingPointLiteralValue getFloatingPointLiteralValue(
Token const& token,
UnownedStringSlice* outSuffix = 0);
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index f37d6a8b6..d0f743e5c 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -1574,6 +1574,12 @@ DIAGNOSTIC(
Error,
invalidFloatingPointLiteralSuffix,
"invalid suffix '$0' on floating-point literal")
+DIAGNOSTIC(
+ 39999,
+ Warning,
+ integerLiteralTooLarge,
+ "integer literal is too large to be represented in a signed integer type, interpreting as "
+ "unsigned")
DIAGNOSTIC(
39999,
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index 61d6ca1dc..8fb3be39c 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -3136,8 +3136,7 @@ static Modifier* ParseSemantic(Parser* parser)
BitFieldModifier* bitWidthMod = parser->astBuilder->create<BitFieldModifier>();
parser->FillPosition(bitWidthMod);
const auto token = parser->tokenReader.advanceToken();
- UnownedStringSlice suffix;
- bitWidthMod->width = getIntegerLiteralValue(token, &suffix);
+ bitWidthMod->width = getIntegerLiteralValue(token);
return bitWidthMod;
}
else if (parser->LookAheadToken(TokenType::CompletionRequest))
@@ -6638,6 +6637,64 @@ static IntegerLiteralValue _fixIntegerLiteral(
return value;
}
+static BaseType _determineNonSuffixedIntegerLiteralType(
+ IntegerLiteralValue value,
+ bool isDecimalBase,
+ Token* token,
+ DiagnosticSink* sink)
+{
+ const uint64_t rawValue = (uint64_t)value;
+
+ /// Non-suffixed integer literal types
+ ///
+ /// The type is the first from the following list in which the value can fit:
+ /// - For decimal bases:
+ /// - `int`
+ /// - `int64_t`
+ /// - For non-decimal bases:
+ /// - `int`
+ /// - `uint`
+ /// - `int64_t`
+ /// - `uint64_t`
+ ///
+ /// The lexer scans the negative(-) part of literal separately, and the value part here
+ /// is always positive hence it is sufficient to only compare with the maximum limits.
+ BaseType baseType;
+ if (rawValue <= INT32_MAX)
+ {
+ baseType = BaseType::Int;
+ }
+ else if ((rawValue <= UINT32_MAX) && !isDecimalBase)
+ {
+ baseType = BaseType::UInt;
+ }
+ else if (rawValue <= INT64_MAX)
+ {
+ baseType = BaseType::Int64;
+ }
+ else
+ {
+ baseType = BaseType::UInt64;
+
+ if (isDecimalBase)
+ {
+ // There is an edge case here where 9223372036854775808 or INT64_MAX + 1
+ // brings us here, but the complete literal is -9223372036854775808 or INT64_MIN and is
+ // valid. Unfortunately because the lexer handles the negative(-) part of the literal
+ // separately it is impossible to know whether the literal has a negative sign or not.
+ // We emit the warning and initially process it as a uint64 anyways, and the negative
+ // sign will be properly parsed and the value will still be properly stored as a
+ // negative INT64_MIN.
+
+ // Decimal integer is too large to be represented as signed.
+ // Output warning that it is represented as unsigned instead.
+ sink->diagnose(*token, Diagnostics::integerLiteralTooLarge);
+ }
+ }
+
+ return baseType;
+}
+
static bool _isCast(Parser* parser, Expr* expr)
{
if (as<PointerTypeExpr>(expr))
@@ -6925,20 +6982,18 @@ static Expr* parseAtomicExpr(Parser* parser)
constExpr->token = token;
UnownedStringSlice suffix;
- IntegerLiteralValue value = getIntegerLiteralValue(token, &suffix);
+ bool isDecimalBase;
+ IntegerLiteralValue value = getIntegerLiteralValue(token, &suffix, &isDecimalBase);
// Look at any suffix on the value
char const* suffixCursor = suffix.begin();
const char* const suffixEnd = suffix.end();
+ const bool suffixExists = (suffixCursor != suffixEnd);
- // If no suffix is defined go with the default
- BaseType suffixBaseType = BaseType::Int;
-
- if (suffixCursor < suffixEnd)
+ // Mark as void, taken as an error
+ BaseType suffixBaseType = BaseType::Void;
+ if (suffixExists)
{
- // Mark as void, taken as an error
- suffixBaseType = BaseType::Void;
-
int lCount = 0;
int uCount = 0;
int zCount = 0;
@@ -7008,6 +7063,14 @@ static Expr* parseAtomicExpr(Parser* parser)
suffixBaseType = BaseType::Int;
}
}
+ else
+ {
+ suffixBaseType = _determineNonSuffixedIntegerLiteralType(
+ value,
+ isDecimalBase,
+ &token,
+ parser->sink);
+ }
value = _fixIntegerLiteral(suffixBaseType, value, &token, parser->sink);