diff --git a/tools/clang/include/clang/Basic/DiagnosticGroups.td b/tools/clang/include/clang/Basic/DiagnosticGroups.td index d1b14a7de9..f0d75709f1 100644 --- a/tools/clang/include/clang/Basic/DiagnosticGroups.td +++ b/tools/clang/include/clang/Basic/DiagnosticGroups.td @@ -808,4 +808,5 @@ def HLSLAvailabilityConstant: DiagGroup<"hlsl-availability-constant">; def HLSLBarrier : DiagGroup<"hlsl-barrier">; def HLSLLegacyLiterals : DiagGroup<"hlsl-legacy-literal">; def HLSLGroupshared202x : DiagGroup<"hlsl-groupshared-202x">; +def HLSL202xExtensions : DiagGroup<"hlsl-202x-extensions", [HLSLGroupshared202x]>; // HLSL Change Ends diff --git a/tools/clang/include/clang/Basic/DiagnosticLexKinds.td b/tools/clang/include/clang/Basic/DiagnosticLexKinds.td index 6ea94dcc56..4266343556 100644 --- a/tools/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/tools/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -658,4 +658,12 @@ def err_pp_eof_in_assume_nonnull : Error< } +// HLSL Change Begin - fixed-size floating-point literal suffixes +def ext_hlsl_fixed_size_float_suffix_202x : ExtWarn< + "fixed-size floating-point literal suffix '%0' is a HLSL 202x extension">, + InGroup; +def err_hlsl_16bit_suffix_requires_native_16bit : Error< + "16-bit floating-point literal suffix '%0' requires '-enable-16bit-types'">; +// HLSL Change End + } diff --git a/tools/clang/lib/Lex/LiteralSupport.cpp b/tools/clang/lib/Lex/LiteralSupport.cpp index 62f241812b..e1aab38357 100644 --- a/tools/clang/lib/Lex/LiteralSupport.cpp +++ b/tools/clang/lib/Lex/LiteralSupport.cpp @@ -609,6 +609,42 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, case 'F': if (!isFPConstant) break; // Error for integer constant. if (isFloat || isLong) break; // FF, LF invalid. + // HLSL Change Begin - fixed-size float suffixes f16/f32/f64 + if (PP.getLangOpts().HLSL && (s + 2) < ThisTokEnd) { + unsigned Width = 0; + if (s[1] == '1' && s[2] == '6') + Width = 16; + else if (s[1] == '3' && s[2] == '2') + Width = 32; + else if (s[1] == '6' && s[2] == '4') + Width = 64; + if (Width != 0) { + StringRef SuffixStr(s, 3); + if (PP.getLangOpts().HLSLVersion < hlsl::LangStd::v202x) { + PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin), + diag::ext_hlsl_fixed_size_float_suffix_202x) + << SuffixStr; + } + if (Width == 16 && PP.getLangOpts().UseMinPrecision) { + PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin), + diag::err_hlsl_16bit_suffix_requires_native_16bit) + << SuffixStr; + hadError = true; + } + // Reuse existing width flags: f16 acts like 'h' (half), f32 like + // 'f' (float), f64 like 'l' (double in HLSL). The source token is + // preserved if anything later needs to distinguish the spellings. + if (Width == 16) + isHalf = true; + else if (Width == 32) + isFloat = true; + else + isLong = true; + s += 2; // The outer loop's ++s consumes the leading 'f'/'F'. + continue; + } + } + // HLSL Change End isFloat = true; continue; // Success. // HLSL Change Starts @@ -718,6 +754,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, isUnsigned = false; isLongLong = false; isFloat = false; + isHalf = false; // HLSL Change isImaginary = false; MicrosoftInteger = 0; diff --git a/tools/clang/test/SemaHLSL/v202x/conforming-literals/fixed-size-float-suffixes-invalid.hlsl b/tools/clang/test/SemaHLSL/v202x/conforming-literals/fixed-size-float-suffixes-invalid.hlsl new file mode 100644 index 0000000000..0260e64edd --- /dev/null +++ b/tools/clang/test/SemaHLSL/v202x/conforming-literals/fixed-size-float-suffixes-invalid.hlsl @@ -0,0 +1,70 @@ +// RUN: %dxc -T lib_6_3 -HV 202x -enable-16bit-types -verify %s + +// Verify that float literal suffixes that look like fixed-size width +// suffixes but specify an unsupported width are rejected. Only 16, 32 and +// 64 are valid widths; everything else must produce an +// "invalid suffix on floating constant" error. + +float plausible_f8() { + // 'f8' would be an 8-bit float, which we don't support. + // expected-error@+1{{invalid suffix 'f8' on floating constant}} + return 1.0f8; +} + +float plausible_F8() { + // expected-error@+1{{invalid suffix 'F8' on floating constant}} + return 1.0F8; +} + +float plausible_f128() { + // 'f128' would be a 128-bit float, which we don't support. + // expected-error@+1{{invalid suffix 'f128' on floating constant}} + return 1.0f128; +} + +float plausible_F128() { + // expected-error@+1{{invalid suffix 'F128' on floating constant}} + return 1.0F128; +} + +float implausible_f23() { + // 'f23' is not a meaningful width but the parser should still reject it. + // expected-error@+1{{invalid suffix 'f23' on floating constant}} + return 1.0f23; +} + +float implausible_f7() { + // 'f7' is not a meaningful width but the parser should still reject it. + // expected-error@+1{{invalid suffix 'f7' on floating constant}} + return 1.0f7; +} + +float implausible_f0() { + // expected-error@+1{{invalid suffix 'f0' on floating constant}} + return 1.0f0; +} + +float implausible_f31() { + // One off from a valid width. + // expected-error@+1{{invalid suffix 'f31' on floating constant}} + return 1.0f31; +} + +float implausible_f33() { + // expected-error@+1{{invalid suffix 'f33' on floating constant}} + return 1.0f33; +} + +float trailing_garbage_after_valid_width() { + // A valid fixed-size suffix followed by extra characters is still an + // invalid suffix. + // expected-error@+1{{invalid suffix 'f32x' on floating constant}} + return 1.0f32x; +} + +float trailing_number_after_valid_width() { + // A valid fixed-size suffix followed by an extra number is still an invalid + // suffix. + // expected-error@+1{{invalid suffix 'f324' on floating constant}} + return 1.0f324; +} diff --git a/tools/clang/test/SemaHLSL/v202x/conforming-literals/fixed-size-float-suffixes-legacy.hlsl b/tools/clang/test/SemaHLSL/v202x/conforming-literals/fixed-size-float-suffixes-legacy.hlsl new file mode 100644 index 0000000000..ef86166f35 --- /dev/null +++ b/tools/clang/test/SemaHLSL/v202x/conforming-literals/fixed-size-float-suffixes-legacy.hlsl @@ -0,0 +1,49 @@ +// RUN: %dxc -T lib_6_3 -HV 2021 -verify %s + +// In HLSL 2021 and earlier, the fixed-size float suffixes f16/f32/f64 should +// still work, but produce an extension warning. With -enable-16bit-types not +// passed, the 16-bit suffix should also error. + +template +struct is_same { + static const bool value = false; +}; + +template +struct is_same { + static const bool value = true; +}; + +float test_f32() { + // expected-warning@+1{{fixed-size floating-point literal suffix 'f32' is a HLSL 202x extension}} + return 1.0f32; +} + +float test_F32() { + // expected-warning@+1{{fixed-size floating-point literal suffix 'F32' is a HLSL 202x extension}} + return 1.0F32; +} + +double test_f64() { + // expected-warning@+1{{fixed-size floating-point literal suffix 'f64' is a HLSL 202x extension}} + return 1.0f64; +} + +double test_F64() { + // expected-warning@+1{{fixed-size floating-point literal suffix 'F64' is a HLSL 202x extension}} + return 1.0F64; +} + +// Without -enable-16bit-types the 16-bit suffix must error (in addition to the +// extension warning). +min16float test_f16() { + // expected-warning@+2{{fixed-size floating-point literal suffix 'f16' is a HLSL 202x extension}} + // expected-error@+1{{16-bit floating-point literal suffix 'f16' requires '-enable-16bit-types'}} + return 1.0f16; +} + +min16float test_F16() { + // expected-warning@+2{{fixed-size floating-point literal suffix 'F16' is a HLSL 202x extension}} + // expected-error@+1{{16-bit floating-point literal suffix 'F16' requires '-enable-16bit-types'}} + return 1.0F16; +} diff --git a/tools/clang/test/SemaHLSL/v202x/conforming-literals/fixed-size-float-suffixes-no-native-16bit.hlsl b/tools/clang/test/SemaHLSL/v202x/conforming-literals/fixed-size-float-suffixes-no-native-16bit.hlsl new file mode 100644 index 0000000000..c327864e5a --- /dev/null +++ b/tools/clang/test/SemaHLSL/v202x/conforming-literals/fixed-size-float-suffixes-no-native-16bit.hlsl @@ -0,0 +1,22 @@ +// RUN: %dxc -T lib_6_3 -HV 202x -verify %s + +// In HLSL 202x mode without -enable-16bit-types, the 16-bit suffix must error +// while f32/f64 are accepted silently. + +float test_f32() { + return 1.0f32; // no diagnostic +} + +double test_f64() { + return 1.0f64; // no diagnostic +} + +min16float test_f16() { + // expected-error@+1{{16-bit floating-point literal suffix 'f16' requires '-enable-16bit-types'}} + return 1.0f16; +} + +min16float test_F16() { + // expected-error@+1{{16-bit floating-point literal suffix 'F16' requires '-enable-16bit-types'}} + return 1.0F16; +} diff --git a/tools/clang/test/SemaHLSL/v202x/conforming-literals/fixed-size-float-suffixes.hlsl b/tools/clang/test/SemaHLSL/v202x/conforming-literals/fixed-size-float-suffixes.hlsl new file mode 100644 index 0000000000..672df1f8c1 --- /dev/null +++ b/tools/clang/test/SemaHLSL/v202x/conforming-literals/fixed-size-float-suffixes.hlsl @@ -0,0 +1,39 @@ +// RUN: %dxc -T lib_6_3 -HV 202x -enable-16bit-types -verify %s + +// Verify that f16/F16/f32/F32/f64/F64 produce the expected types in HLSL 202x +// with native 16-bit types enabled. + +template +struct is_same { + static const bool value = false; +}; + +template +struct is_same { + static const bool value = true; +}; + +// expected-no-diagnostics + +// 16-bit suffix -> float16_t (a.k.a. half / HalfTy). +_Static_assert(is_same<__decltype(1.0f16), half>::value, "1.0f16 is half"); +_Static_assert(is_same<__decltype(1.0F16), half>::value, "1.0F16 is half"); +_Static_assert(is_same<__decltype(2.5e1f16), half>::value, "2.5e1f16 is half"); + +// 32-bit suffix -> float, regardless of UseMinPrecision. +_Static_assert(is_same<__decltype(1.0f32), float>::value, "1.0f32 is float"); +_Static_assert(is_same<__decltype(1.0F32), float>::value, "1.0F32 is float"); +_Static_assert(is_same<__decltype(0.5e0f32), float>::value, "0.5e0f32 is float"); + +// 64-bit suffix -> double. +_Static_assert(is_same<__decltype(1.0f64), double>::value, "1.0f64 is double"); +_Static_assert(is_same<__decltype(1.0F64), double>::value, "1.0F64 is double"); +_Static_assert(is_same<__decltype(0.5e0f64), double>::value, "0.5e0f64 is double"); + +// Sanity check: the plain 'f' and 'h' suffixes still work. +_Static_assert(is_same<__decltype(1.0f), float>::value, "1.0f is float"); +_Static_assert(is_same<__decltype(1.0h), half>::value, "1.0h is half"); +_Static_assert(is_same<__decltype(1.0l), double>::value, "1.0l is double"); + +// The fixed-size suffix must not collide with an integer suffix. +_Static_assert(is_same<__decltype(1.f32), float>::value, ".f32 with no fraction digits is float");