Author: Deric C.
Date: 2026-05-05T09:47:32-07:00
New Revision: 86b346da50a6629bdef1c49769870b10e20a2b01

URL: 
https://github.com/llvm/llvm-project/commit/86b346da50a6629bdef1c49769870b10e20a2b01
DIFF: 
https://github.com/llvm/llvm-project/commit/86b346da50a6629bdef1c49769870b10e20a2b01.diff

LOG: [HLSL] For builtins aliases, apply implicit conversions before running 
custom type checking (#195365)

Fixes https://github.com/llvm/llvm-project/issues/195329 by making HLSL
builtin aliases apply implicit conversions before running custom type
checking.

After this PR:
- There are no more size 1 vectors being passed and returned to/from
aliased Clang builtins because they get truncated to scalars due to the
HLSL alias builtin not having explicit size 1 vector overloads.
- HLSL alias builtins no longer accept matrices unless they have
explicit matrix overloads. Matrices get implicitly truncated to scalars
and resolve to the scalar Clang builtin being aliased.
- Many calls with mismatched vector sizes no longer error with
`arguments are of different types` and instead follow Clang's overload
resolution rules with respect to HLSL's implicit conversion sequences.
(e.g., `dot(float3, float2)` -> `dot(float2, float2)` with warning)
- Calls with implicitly-convertible types no longer error. They are now
implicitly converted, and with a warning in some cases. (e.g.,
`f16tof32(bool)` -> `f16tof32(uint)` without warning, but
`f16tof32(short)` -> `f16tof32(uint)` with warning).

Assisted-by: Claude Opus 4.6

Added: 
    

Modified: 
    clang/lib/Sema/SemaExpr.cpp
    clang/test/CodeGenHLSL/builtins/fma.hlsl
    clang/test/SemaHLSL/BuiltIns/clamp-errors.hlsl
    clang/test/SemaHLSL/BuiltIns/dot-errors.hlsl
    clang/test/SemaHLSL/BuiltIns/f16tof32-errors.hlsl
    clang/test/SemaHLSL/BuiltIns/f32tof16-errors.hlsl
    clang/test/SemaHLSL/BuiltIns/fma-errors.hlsl
    clang/test/SemaHLSL/BuiltIns/lerp-errors.hlsl
    clang/test/SemaHLSL/BuiltIns/mad-errors.hlsl

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index c494669420282..98062afae4577 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -6076,9 +6076,14 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
                               SourceLocation RParenLoc,
                               bool IsExecConfig) {
   // Bail out early if calling a builtin with custom typechecking.
+  // For HLSL builtin aliases, argument conversion is still needed because
+  // overload resolution may have selected a conversion sequence (e.g.,
+  // vector-to-scalar truncation) that must be applied before the custom
+  // type checker runs.
   if (FDecl)
     if (unsigned ID = FDecl->getBuiltinID())
-      if (Context.BuiltinInfo.hasCustomTypechecking(ID))
+      if (Context.BuiltinInfo.hasCustomTypechecking(ID) &&
+          !(Context.getLangOpts().HLSL && FDecl->hasAttr<BuiltinAliasAttr>()))
         return false;
 
   // C99 6.5.2.2p7 - the arguments are implicitly converted, as if by
@@ -7205,6 +7210,18 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, 
NamedDecl *NDecl,
 
   // Bail out early if calling a builtin with custom type checking.
   if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID)) {
+    // For HLSL builtin aliases, the call was resolved via overload resolution
+    // which may have selected a conversion sequence (e.g., vector-to-scalar
+    // truncation). Convert arguments to match the declared prototype before
+    // the custom type checker runs, otherwise the builtin will operate on
+    // the unconverted argument types.
+    if (getLangOpts().HLSL && FDecl && FDecl->hasAttr<BuiltinAliasAttr>()) {
+      if (const auto *P = FDecl->getType()->getAs<FunctionProtoType>()) {
+        if (ConvertArgumentsForCall(TheCall, Fn, FDecl, P, Args, RParenLoc,
+                                    IsExecConfig))
+          return ExprError();
+      }
+    }
     ExprResult E = CheckBuiltinFunctionCall(FDecl, BuiltinID, TheCall);
     if (!E.isInvalid() && Context.BuiltinInfo.isImmediate(BuiltinID))
       E = CheckForImmediateInvocation(E, FDecl);

diff  --git a/clang/test/CodeGenHLSL/builtins/fma.hlsl 
b/clang/test/CodeGenHLSL/builtins/fma.hlsl
index 3d9549197035d..93a2705c51634 100644
--- a/clang/test/CodeGenHLSL/builtins/fma.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/fma.hlsl
@@ -25,10 +25,15 @@ double3 fma_double3(double3 a, double3 b, double3 c) { 
return fma(a, b, c); }
 // CHECK: ret <4 x double>
 double4 fma_double4(double4 a, double4 b, double4 c) { return fma(a, b, c); }
 
-// CHECK-LABEL: define {{.*}} <1 x double> @{{.*}}fma_double1x1{{.*}}(
-// CHECK: call reassoc nnan ninf nsz arcp afn <1 x double> @llvm.fma.v1f64(<1 
x double>
-// CHECK: ret <1 x double>
-double1x1 fma_double1x1(double1x1 a, double1x1 b, double1x1 c) {
+// No double1x1 fma overload exists, so overload resolution picks the scalar
+// double overload. The double1x1 matrix arguments are truncated to scalar.
+// CHECK-LABEL: define {{.*}} double @{{.*}}fma_double1x1{{.*}}(
+// CHECK: %cast.mtrunc = extractelement <1 x double>
+// CHECK: %cast.mtrunc{{[0-9]+}} = extractelement <1 x double>
+// CHECK: %cast.mtrunc{{[0-9]+}} = extractelement <1 x double>
+// CHECK: call reassoc nnan ninf nsz arcp afn double @llvm.fma.f64(double
+// CHECK: ret double
+double fma_double1x1(double1x1 a, double1x1 b, double1x1 c) {
   return fma(a, b, c);
 }
 

diff  --git a/clang/test/SemaHLSL/BuiltIns/clamp-errors.hlsl 
b/clang/test/SemaHLSL/BuiltIns/clamp-errors.hlsl
index bbe567b6d6ac1..2924639b92ca9 100644
--- a/clang/test/SemaHLSL/BuiltIns/clamp-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/clamp-errors.hlsl
@@ -35,9 +35,11 @@ float2 test_scalar_first_arg3(float p0, float2 p1) {
   // expected-error@-1 {{call to 'clamp' is ambiguous}}
 }
 
-float3 test_clamp_vector_size_last_arg_mismatch(float3 p0, float2 p1) {
+// With implicit conversions, the float2 overload is selected and float3 args
+// are truncated to float2.
+float2 test_clamp_vector_size_last_arg_mismatch(float3 p0, float2 p1) {
   return clamp(p0, p0, p1);
-  // expected-error@-1 {{arguments are of 
diff erent types ('vector<[...], 3>' vs 'vector<[...], 2>')}}
+  // expected-warning@-1 2{{implicit conversion truncates vector: 'float3' 
(aka 'vector<float, 3>') to 'vector<float, 2>' (vector of 2 'float' values)}}
 }
 
 typedef float float5 __attribute__((ext_vector_type(5)));

diff  --git a/clang/test/SemaHLSL/BuiltIns/dot-errors.hlsl 
b/clang/test/SemaHLSL/BuiltIns/dot-errors.hlsl
index f514a04eb9f49..0f62ba3dbdbf1 100644
--- a/clang/test/SemaHLSL/BuiltIns/dot-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/dot-errors.hlsl
@@ -15,9 +15,11 @@ float test_dot_no_second_arg(float2 p0) {
   // expected-error@-1 {{no matching function for call to 'dot'}}
 }
 
+// With implicit conversions, the float2 overload is selected and float3 is
+// truncated to float2 with a warning (no longer a type-mismatch error).
 float test_dot_vector_size_mismatch(float3 p0, float2 p1) {
   return dot(p0, p1);
-  // expected-error@-1 {{arguments are of 
diff erent types ('vector<[...], 3>' vs 'vector<[...], 2>')}}
+  // expected-warning@-1 {{implicit conversion truncates vector: 'float3' (aka 
'vector<float, 3>') to 'vector<float, 2>' (vector of 2 'float' values)}}
 }
 
 float test_dot_builtin_vector_size_mismatch(float3 p0, float2 p1) {

diff  --git a/clang/test/SemaHLSL/BuiltIns/f16tof32-errors.hlsl 
b/clang/test/SemaHLSL/BuiltIns/f16tof32-errors.hlsl
index 32abf5113fdd4..a39a9970a176c 100644
--- a/clang/test/SemaHLSL/BuiltIns/f16tof32-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/f16tof32-errors.hlsl
@@ -77,58 +77,69 @@ float f16tof32_too_many_arg(uint p0) {
   // expected-error@-1 {{no matching function for call to 'f16tof32'}}
 }
 
+// Overload resolution selects uint f16tof32(uint); bool is implicitly 
converted to uint.
 float f16tof32_bool(bool p0) {
   return f16tof32(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of unsigned 
integer types (was 'bool')}}
 }
 
+// Overload resolution selects an overload; bool3 is implicitly converted.
 float f16tof32_bool3(bool3 p0) {
   return f16tof32(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of unsigned 
integer types (was 'bool3' (aka 'vector<bool, 3>'))}}
+  // expected-warning@-1 {{implicit conversion turns vector to scalar: 
'vector<float, 3>' (vector of 3 'float' values) to 'float'}}
 }
 
 
+// Overload resolution selects uint f16tof32(uint); short is implicitly 
converted to uint.
 float f16tof32_int16_t(short p0) {
   return f16tof32(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of unsigned 
integer types (was 'short')}}
+  // expected-warning@-1 {{implicit conversion changes signedness: 'short' to 
'uint' (aka 'unsigned int')}}
 }
 
+// Overload resolution selects uint f16tof32(uint); unsigned short is 
implicitly converted to uint.
 float f16tof32_int16_t(unsigned short p0) {
   return f16tof32(p0);
-  // expected-error@-1 {{incorrect number of bits in integer (expected 32 
bits, have 16)}}
 }
 
+// Overload resolution selects uint f16tof32(uint); int is implicitly 
converted to uint.
 float f16tof32_int(int p0) {
   return f16tof32(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of unsigned 
integer types (was 'int')}}
+  // expected-warning@-1 {{implicit conversion changes signedness: 'int' to 
'uint' (aka 'unsigned int')}}
 }
 
+// Overload resolution selects uint f16tof32(uint); long is implicitly 
converted to uint.
 float f16tof32_int64_t(long p0) {
   return f16tof32(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of unsigned 
integer types (was 'long')}}
+  // expected-warning@-1 {{implicit conversion loses integer precision: 'long' 
to 'uint' (aka 'unsigned int')}}
 }
 
+// Overload resolution selects an overload; int3 is implicitly converted.
 float2 f16tof32_int2_to_float2_promotion(int3 p0) {
   return f16tof32(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of unsigned 
integer types (was 'int3' (aka 'vector<int, 3>'))}}
+  // expected-warning@-1 {{implicit conversion truncates vector: 
'vector<float, 3>' (vector of 3 'float' values) to 'vector<float, 2>' (vector 
of 2 'float' values)}}
+  // expected-warning@-2 {{implicit conversion changes signedness: 'int3' (aka 
'vector<int, 3>') to 'vector<uint, 3>' (vector of 3 'uint' values)}}
 }
 
+// Overload resolution selects uint f16tof32(uint); half is implicitly 
converted to uint.
 float f16tof32_half(half p0) {
   return f16tof32(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of unsigned 
integer types (was 'half')}}
+  // expected-warning@-1 {{implicit conversion turns floating-point number 
into integer: 'half' to 'uint' (aka 'unsigned int')}}
 }
 
+// Overload resolution selects an overload; half2 is implicitly converted.
 float f16tof32_half2(half2 p0) {
   return f16tof32(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of unsigned 
integer types (was 'half2' (aka 'vector<half, 2>'))}}
+  // expected-warning@-1 {{implicit conversion turns vector to scalar: 
'vector<float, 2>' (vector of 2 'float' values) to 'float'}}
+  // expected-warning@-2 {{implicit conversion turns floating-point number 
into integer: 'half2' (aka 'vector<half, 2>') to 'vector<uint, 2>' (vector of 2 
'uint' values)}}
 }
 
+// Overload resolution selects uint f16tof32(uint); float is implicitly 
converted to uint.
 float f16tof32_float(float p0) {
   return f16tof32(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of unsigned 
integer types (was 'float')}}
+  // expected-warning@-1 {{implicit conversion turns floating-point number 
into integer: 'float' to 'uint' (aka 'unsigned int')}}
 }
 
+// Overload resolution selects uint f16tof32(uint); double is implicitly 
converted to uint.
 float f16tof32_double(double p0) {
   return f16tof32(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of unsigned 
integer types (was 'double')}}
+  // expected-warning@-1 {{implicit conversion turns floating-point number 
into integer: 'double' to 'uint' (aka 'unsigned int')}}
 }

diff  --git a/clang/test/SemaHLSL/BuiltIns/f32tof16-errors.hlsl 
b/clang/test/SemaHLSL/BuiltIns/f32tof16-errors.hlsl
index 04479935754a6..b2b52f9b153ab 100644
--- a/clang/test/SemaHLSL/BuiltIns/f32tof16-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/f32tof16-errors.hlsl
@@ -77,58 +77,66 @@ uint f32tof16_too_many_arg(uint p0) {
   // expected-error@-1 {{no matching function for call to 'f32tof16'}}
 }
 
+// Overload resolution selects uint f32tof16(float); bool is implicitly 
converted to float.
 uint f32tof16_bool(bool p0) {
   return f32tof16(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of 
floating-point types (was 'bool')}}
 }
 
+// Overload resolution selects an overload; bool3 is implicitly converted.
 uint f32tof16_bool3(bool3 p0) {
   return f32tof16(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of 
floating-point types (was 'bool3' (aka 'vector<bool, 3>'))}}
+  // expected-warning@-1 {{implicit conversion turns vector to scalar: 
'vector<unsigned int, 3>' (vector of 3 'unsigned int' values) to 'unsigned 
int'}}
 }
 
 
+// Overload resolution selects uint f32tof16(float); short is implicitly 
converted to float.
 uint f32tof16_int16_t(short p0) {
   return f32tof16(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of 
floating-point types (was 'short')}}
 }
 
+// Overload resolution selects uint f32tof16(float); unsigned short is 
implicitly converted to float.
 uint f32tof16_int16_t(unsigned short p0) {
   return f32tof16(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of 
floating-point types (was 'unsigned short')}}
 }
 
+// Overload resolution selects uint f32tof16(float); int is implicitly 
converted to float.
 uint f32tof16_int(int p0) {
   return f32tof16(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of 
floating-point types (was 'int')}}
+  // expected-warning@-1 {{implicit conversion from 'int' to 'float' may lose 
precision}}
 }
 
+// Overload resolution selects uint f32tof16(float); long is implicitly 
converted to float.
 uint f32tof16_int64_t(long p0) {
   return f32tof16(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of 
floating-point types (was 'long')}}
+  // expected-warning@-1 {{implicit conversion from 'long' to 'float' may lose 
precision}}
 }
 
+// Overload resolution selects an overload; int3 is implicitly converted.
 uint2 f32tof16_int2_to_float2_promotion(int3 p0) {
   return f32tof16(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of 
floating-point types (was 'int3' (aka 'vector<int, 3>'))}}
+  // expected-warning@-1 {{implicit conversion truncates vector: 
'vector<unsigned int, 3>' (vector of 3 'unsigned int' values) to 
'vector<unsigned int, 2>' (vector of 2 'unsigned int' values)}}
+  // expected-warning@-2 {{implicit conversion from 'int3' (aka 'vector<int, 
3>') to 'vector<float, 3>' (vector of 3 'float' values) may lose precision}}
 }
 
+// Overload resolution selects uint f32tof16(float); half is implicitly 
converted to float.
 uint f32tof16_half(half p0) {
   return f32tof16(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of 
floating-point types (was 'half')}}
 }
 
+// Overload resolution selects an overload; half2 is implicitly converted.
 uint f32tof16_half2(half2 p0) {
   return f32tof16(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of 
floating-point types (was 'half2' (aka 'vector<half, 2>'))}}
+  // expected-warning@-1 {{implicit conversion turns vector to scalar: 
'vector<unsigned int, 2>' (vector of 2 'unsigned int' values) to 'unsigned 
int'}}
 }
 
+// Overload resolution selects uint f32tof16(float); uint is implicitly 
converted to float.
 uint f32tof16_float(uint p0) {
   return f32tof16(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of 
floating-point types (was 'uint' (aka 'unsigned int'))}}
+  // expected-warning@-1 {{implicit conversion from 'uint' (aka 'unsigned 
int') to 'float' may lose precision}}
 }
 
+// Overload resolution selects uint f32tof16(float); double is implicitly 
converted to float.
 uint f32tof16_double(double p0) {
   return f32tof16(p0);
-  // expected-error@-1 {{1st argument must be a scalar or vector of 
floating-point types (was 'double')}}
+  // expected-warning@-1 {{implicit conversion loses floating-point precision: 
'double' to 'float'}}
 }

diff  --git a/clang/test/SemaHLSL/BuiltIns/fma-errors.hlsl 
b/clang/test/SemaHLSL/BuiltIns/fma-errors.hlsl
index a454f2df4d508..e6a2dd6c052be 100644
--- a/clang/test/SemaHLSL/BuiltIns/fma-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/fma-errors.hlsl
@@ -1,70 +1,88 @@
 // RUN: %clang_cc1 -finclude-default-header -fnative-half-type -x hlsl \
-// RUN:   -triple dxil-pc-shadermodel6.6-library %s \
+// RUN:   -triple dxil-pc-shadermodel6.6-library %s -Wdouble-promotion \
 // RUN:   -emit-llvm-only -disable-llvm-passes -verify \
 // RUN:   -verify-ignore-unexpected=note
 // RUN: %clang_cc1 -finclude-default-header -fnative-half-type -x hlsl \
-// RUN:   -triple spirv-unknown-vulkan-compute %s \
+// RUN:   -triple spirv-unknown-vulkan-compute %s -Wdouble-promotion \
 // RUN:   -emit-llvm-only -disable-llvm-passes -verify \
 // RUN:   -verify-ignore-unexpected=note
 
 float bad_float(float a, float b, float c) {
+  // Overload resolution selects 'double fma(double, double, double)'; args 
promoted to double.
   return fma(a, b, c);
-  // expected-error@-1 {{1st argument must be a scalar, vector, or matrix of 
double type (was 'float')}}
+  // expected-warning@-1 3{{implicit conversion increases floating-point 
precision: 'float' to 'double'}}
+  // expected-warning@-2 {{implicit conversion loses floating-point precision: 
'double' to 'float'}}
 }
 
 float2 bad_float2(float2 a, float2 b, float2 c) {
+  // Overload resolution selects 'double2 fma(double2, double2, double2)'; 
args promoted to double2.
   return fma(a, b, c);
-  // expected-error@-1 {{1st argument must be a scalar, vector, or matrix of 
double type (was 'float2' (aka 'vector<float, 2>'))}}
+  // expected-warning@-1 3{{implicit conversion increases floating-point 
precision: 'float2' (aka 'vector<float, 2>') to 'vector<double, 2>' (vector of 
2 'double' values)}}
+  // expected-warning@-2 {{implicit conversion loses floating-point precision: 
'vector<double, 2>' (vector of 2 'double' values) to 'vector<float, 2>' (vector 
of 2 'float' values)}}
 }
 
 float2x2 bad_float2x2(float2x2 a, float2x2 b, float2x2 c) {
+  // Overload resolution selects 'double2x2 fma(double2x2, double2x2, 
double2x2)'; args promoted.
   return fma(a, b, c);
-  // expected-error@-1 {{1st argument must be a scalar, vector, or matrix of 
double type (was 'float2x2' (aka 'matrix<float, 2, 2>'))}}
+  // expected-warning@-1 3{{implicit conversion increases floating-point 
precision: 'float2x2' (aka 'matrix<float, 2, 2>') to 'matrix<double, 2, 2>'}}
+  // expected-warning@-2 {{implicit conversion loses floating-point precision: 
'matrix<double, 2, 2>' to 'matrix<float, 2, 2>'}}
 }
 
 half bad_half(half a, half b, half c) {
+  // Overload resolution selects 'double fma(double, double, double)'; args 
promoted to double.
   return fma(a, b, c);
-  // expected-error@-1 {{1st argument must be a scalar, vector, or matrix of 
double type (was 'half')}}
+  // expected-warning@-1 3{{implicit conversion increases floating-point 
precision: 'half' to 'double'}}
+  // expected-warning@-2 {{implicit conversion loses floating-point precision: 
'double' to 'half'}}
 }
 
 half2 bad_half2(half2 a, half2 b, half2 c) {
+  // Overload resolution selects 'double2 fma(double2, double2, double2)'; 
args promoted.
   return fma(a, b, c);
-  // expected-error@-1 {{1st argument must be a scalar, vector, or matrix of 
double type (was 'half2' (aka 'vector<half, 2>'))}}
+  // expected-warning@-1 3{{implicit conversion increases floating-point 
precision: 'half2' (aka 'vector<half, 2>') to 'vector<double, 2>' (vector of 2 
'double' values)}}
+  // expected-warning@-2 {{implicit conversion loses floating-point precision: 
'vector<double, 2>' (vector of 2 'double' values) to 'vector<half, 2>' (vector 
of 2 'half' values)}}
 }
 
 half2x2 bad_half2x2(half2x2 a, half2x2 b, half2x2 c) {
+  // Overload resolution selects 'double2x2 fma(double2x2, double2x2, 
double2x2)'; args promoted.
   return fma(a, b, c);
-  // expected-error@-1 {{1st argument must be a scalar, vector, or matrix of 
double type (was 'half2x2' (aka 'matrix<half, 2, 2>'))}}
+  // expected-warning@-1 3{{implicit conversion increases floating-point 
precision: 'half2x2' (aka 'matrix<half, 2, 2>') to 'matrix<double, 2, 2>'}}
+  // expected-warning@-2 {{implicit conversion loses floating-point precision: 
'matrix<double, 2, 2>' to 'matrix<half, 2, 2>'}}
 }
 
 double mixed_bad_second(double a, float b, double c) {
+  // Overload resolution selects 'double fma(double, double, double)'; float 
promoted to double.
   return fma(a, b, c);
-  // expected-error@-1 {{arguments are of 
diff erent types ('double' vs 'float')}}
+  // expected-warning@-1 {{implicit conversion increases floating-point 
precision: 'float' to 'double'}}
 }
 
 double mixed_bad_third(double a, double b, half c) {
+  // Overload resolution selects 'double fma(double, double, double)'; half 
promoted to double.
   return fma(a, b, c);
-  // expected-error@-1 {{arguments are of 
diff erent types ('double' vs 'half')}}
+  // expected-warning@-1 {{implicit conversion increases floating-point 
precision: 'half' to 'double'}}
 }
 
 double2 mixed_bad_second_vec(double2 a, float2 b, double2 c) {
+  // Overload resolution selects 'double2 fma(double2, double2, double2)'; 
float2 promoted.
   return fma(a, b, c);
-  // expected-error@-1 {{arguments are of 
diff erent types ('vector<double, [...]>' vs 'vector<float, [...]>')}}
+  // expected-warning@-1 {{implicit conversion increases floating-point 
precision: 'float2' (aka 'vector<float, 2>') to 'vector<double, 2>' (vector of 
2 'double' values)}}
 }
 
 double2 mixed_bad_third_vec(double2 a, double2 b, float2 c) {
+  // Overload resolution selects 'double2 fma(double2, double2, double2)'; 
float2 promoted.
   return fma(a, b, c);
-  // expected-error@-1 {{arguments are of 
diff erent types ('vector<double, [...]>' vs 'vector<float, [...]>')}}
+  // expected-warning@-1 {{implicit conversion increases floating-point 
precision: 'float2' (aka 'vector<float, 2>') to 'vector<double, 2>' (vector of 
2 'double' values)}}
 }
 
 double2x2 mixed_bad_second_mat(double2x2 a, float2x2 b, double2x2 c) {
+  // Overload resolution selects 'double2x2 fma(double2x2, double2x2, 
double2x2)'; float2x2 promoted.
   return fma(a, b, c);
-  // expected-error@-1 {{arguments are of 
diff erent types ('matrix<double, [2 * ...]>' vs 'matrix<float, [2 * ...]>')}}
+  // expected-warning@-1 {{implicit conversion increases floating-point 
precision: 'float2x2' (aka 'matrix<float, 2, 2>') to 'matrix<double, 2, 2>'}}
 }
 
 double2x2 mixed_bad_third_mat(double2x2 a, double2x2 b, half2x2 c) {
+  // Overload resolution selects 'double2x2 fma(double2x2, double2x2, 
double2x2)'; half2x2 promoted.
   return fma(a, b, c);
-  // expected-error@-1 {{arguments are of 
diff erent types ('matrix<double, [2 * ...]>' vs 'matrix<half, [2 * ...]>')}}
+  // expected-warning@-1 {{implicit conversion increases floating-point 
precision: 'half2x2' (aka 'matrix<half, 2, 2>') to 'matrix<double, 2, 2>'}}
 }
 
 double shape_mismatch_second(double a, double2 b, double c) {
@@ -84,30 +102,40 @@ double2x2 shape_mismatch_scalar_mat(double2x2 a, double b, 
double2x2 c) {
 
 double2x2 shape_mismatch_vec_mat(double2x2 a, double2 b, double2x2 c) {
   return fma(a, b, c);
-  // expected-error@-1 {{arguments are of 
diff erent types ('double2x2' (aka 'matrix<double, 2, 2>') vs 'double2' (aka 
'vector<double, 2>'))}}
+  // Overload resolution selects the scalar 'double fma(double, double, 
double)'
+  // overload; vector/matrix arguments are truncated to scalar.
+  // expected-warning@-3 {{implicit conversion turns matrix to scalar: 
'double2x2' (aka 'matrix<double, 2, 2>') to 'double'}}
+  // expected-warning@-4 {{implicit conversion turns vector to scalar: 
'double2' (aka 'vector<double, 2>') to 'double'}}
+  // expected-warning@-5 {{implicit conversion turns matrix to scalar: 
'double2x2' (aka 'matrix<double, 2, 2>') to 'double'}}
 }
 
 int bad_int(int a, int b, int c) {
+  // Overload resolution selects 'double fma(double, double, double)'; ints 
promoted to double.
   return fma(a, b, c);
-  // expected-error@-1 {{1st argument must be a scalar or vector of 
floating-point types (was 'int')}}
+  // expected-warning@-1 {{implicit conversion turns floating-point number 
into integer: 'double' to 'int'}}
 }
 
 int2 bad_int2(int2 a, int2 b, int2 c) {
+  // Overload resolution selects 'double2 fma(double2, double2, double2)'; 
int2 promoted.
   return fma(a, b, c);
-  // expected-error@-1 {{1st argument must be a scalar or vector of 
floating-point types (was 'int2' (aka 'vector<int, 2>'))}}
+  // expected-warning@-1 {{implicit conversion turns floating-point number 
into integer: 'vector<double, 2>' (vector of 2 'double' values) to 'vector<int, 
2>' (vector of 2 'int' values)}}
 }
 
 bool bad_bool(bool a, bool b, bool c) {
+  // Overload resolution selects 'double fma(double, double, double)'; bools 
promoted to double.
   return fma(a, b, c);
-  // expected-error@-1 {{1st argument must be a scalar or vector of 
floating-point types (was 'bool')}}
+  // expected-warning@-1 {{implicit conversion turns floating-point number 
into integer: 'double' to 'bool'}}
+  // expected-warning@-2 {{implicit conversion turns floating-point number 
into bool: 'double' to 'bool'}}
 }
 
 bool2 bad_bool2(bool2 a, bool2 b, bool2 c) {
+  // Overload resolution selects 'double2 fma(double2, double2, double2)'; 
bool2 promoted.
   return fma(a, b, c);
-  // expected-error@-1 {{1st argument must be a scalar or vector of 
floating-point types (was 'bool2' (aka 'vector<bool, 2>'))}}
+  // expected-warning@-1 {{implicit conversion turns floating-point number 
into integer: 'vector<double, 2>' (vector of 2 'double' values) to 
'vector<bool, 2>' (vector of 2 'bool' values)}}
 }
 
 bool2x2 bad_bool2x2(bool2x2 a, bool2x2 b, bool2x2 c) {
+  // Overload resolution selects 'double2x2 fma(double2x2, double2x2, 
double2x2)'; bool2x2 promoted.
   return fma(a, b, c);
-  // expected-error@-1 {{1st argument must be a scalar or vector of 
floating-point types (was 'bool2x2' (aka 'matrix<bool, 2, 2>'))}}
+  // expected-warning@-1 {{implicit conversion turns floating-point number 
into integer: 'matrix<double, 2, 2>' to 'matrix<bool, 2, 2>'}}
 }

diff  --git a/clang/test/SemaHLSL/BuiltIns/lerp-errors.hlsl 
b/clang/test/SemaHLSL/BuiltIns/lerp-errors.hlsl
index 22720a4a37d02..bc82991eb3e6b 100644
--- a/clang/test/SemaHLSL/BuiltIns/lerp-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/lerp-errors.hlsl
@@ -25,14 +25,18 @@ float2 test_lerp_vector_trunc_warn1(float3 p0) {
   // expected-warning@-1 {{implicit conversion truncates vector: 'float3' (aka 
'vector<float, 3>') to 'vector<float, 2>' (vector of 2 'float' values)}}
 }
 
+// With implicit conversions, the float2 overload is selected and float3 args
+// are implicitly truncated to float2 (warnings instead of type-mismatch 
error).
 float2 test_lerp_vector_size_mismatch1(float3 p0, float2 p1) {
   return lerp(p0, p0, p1);
-  // expected-error@-1 {{all arguments to 'lerp' must have the same type}}
+  // expected-warning@-1 2{{implicit conversion truncates vector: 'float3' 
(aka 'vector<float, 3>') to 'vector<float, 2>' (vector of 2 'float' values)}}
 }
 
+// With implicit conversions, the float2 overload is selected and float3 args
+// are implicitly truncated to float2 (warnings instead of type-mismatch 
error).
 float2 test_lerp_vector_size_mismatch2(float3 p0, float2 p1) {
   return lerp(p0, p1, p0);
-  // expected-error@-1 {{all arguments to 'lerp' must have the same type}}
+  // expected-warning@-1 2{{implicit conversion truncates vector: 'float3' 
(aka 'vector<float, 3>') to 'vector<float, 2>' (vector of 2 'float' values)}}
 }
 
 float2 test_lerp_builtin_vector_size_mismatch_Arg1(float3 p0, float2 p1) {

diff  --git a/clang/test/SemaHLSL/BuiltIns/mad-errors.hlsl 
b/clang/test/SemaHLSL/BuiltIns/mad-errors.hlsl
index 0e9dda7055f98..3d39b5e7dfea6 100644
--- a/clang/test/SemaHLSL/BuiltIns/mad-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/mad-errors.hlsl
@@ -20,9 +20,11 @@ float2 test_mad_no_second_arg(float2 p0) {
   // expected-error@-1 {{no matching function for call to 'mad'}}
 }
 
+// With implicit conversions, the float2 overload is selected and float3 args
+// are implicitly truncated to float2 (warnings instead of type-mismatch 
error).
 float2 test_mad_vector_size_mismatch(float3 p0, float2 p1) {
   return mad(p0, p0, p1);
-  // expected-error@-1 {{arguments are of 
diff erent types ('vector<[...], 3>' vs 'vector<[...], 2>')}}
+  // expected-warning@-1 2{{implicit conversion truncates vector: 'float3' 
(aka 'vector<float, 3>') to 'vector<float, 2>' (vector of 2 'float' values)}}
 }
 
 float2 test_mad_builtin_vector_size_mismatch(float3 p0, float2 p1) {


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to