Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -1915,7 +1915,7 @@ /// IsIntegralPromotion - Determines whether the conversion from the /// expression From (whose potentially-adjusted type is FromType) to /// ToType is an integral promotion (C++ 4.5). If so, returns true and -/// sets PromotedType to the promoted type. +/// sets From to the promoted type. bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { const BuiltinType *To = ToType->getAs(); // All integers are built-in. @@ -2063,7 +2063,7 @@ /// IsFloatingPointPromotion - Determines whether the conversion from /// FromType to ToType is a floating point promotion (C++ 4.6). If so, -/// returns true and sets PromotedType to the promoted type. +/// returns true. bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) { if (const BuiltinType *FromBuiltin = FromType->getAs()) if (const BuiltinType *ToBuiltin = ToType->getAs()) { @@ -2073,20 +2073,14 @@ ToBuiltin->getKind() == BuiltinType::Double) return true; - // C99 6.3.1.5p1: - // When a float is promoted to double or long double, or a - // double is promoted to long double [...]. - if (!getLangOpts().CPlusPlus && - (FromBuiltin->getKind() == BuiltinType::Float || - FromBuiltin->getKind() == BuiltinType::Double) && - (ToBuiltin->getKind() == BuiltinType::LongDouble || - ToBuiltin->getKind() == BuiltinType::Float128)) - return true; - - // Half can be promoted to float. - if (!getLangOpts().NativeHalfType && - FromBuiltin->getKind() == BuiltinType::Half && - ToBuiltin->getKind() == BuiltinType::Float) + /// Behave as if C++ 4.6 was modified by: + /// - Inserting a paragraph: + /// "A prvalue of type half can be converted to a prvalue of type + /// double. The value is unchanged." + /// - Updating paragraph 2 to: + /// "These conversions are called floating point promotions." + if (FromBuiltin->getKind() == BuiltinType::Half && + ToBuiltin->getKind() == BuiltinType::Double) return true; } Index: clang/test/CodeGenCXX/fp16-overload.cpp =================================================================== --- clang/test/CodeGenCXX/fp16-overload.cpp +++ clang/test/CodeGenCXX/fp16-overload.cpp @@ -1,10 +1,33 @@ // RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-linux-gnueabi %s | FileCheck %s +// RUN: %clang_cc1 -DWITH_AMBIGUOUS -verify %s +// RUN: %clang_cc1 -DWITH_AMBIGUOUS -fnative-half-type -fallow-half-arguments-and-returns -verify %s -extern int foo(float x); -extern int foo(double x); +typedef __fp16 half; +half x; -__fp16 a; +void half_to_float_or_double(float x); +void half_to_float_or_double(double x); -// CHECK: call i32 @_Z3foof -// CHECK-NOT: call i32 @_Z3food -int bar (void) { return foo(a); } +// CHECK: call void @_Z23half_to_float_or_doubled +// CHECK-NOT: call void @_Z23half_to_float_or_doublef +void test1() { + half_to_float_or_double(x); +} + +extern void half_to_int_or_double(int x); +extern void half_to_int_or_double(double x); + +// CHECK: call void @_Z21half_to_int_or_doubled +// CHECK-NOT: call void @_Z21half_to_int_or_doublei +void test2() { + half_to_int_or_double(x); +} + +#ifdef WITH_AMBIGUOUS +extern void half_to_int_or_float(int x); // expected-note {{candidate function}} +extern void half_to_int_or_float(float x); // expected-note {{candidate function}} + +void test3() { + half_to_int_or_float(x); // expected-error {{call to 'half_to_int_or_float' is ambiguous}} +} +#endif Index: clang/test/Sema/overloadable-complex.c =================================================================== --- clang/test/Sema/overloadable-complex.c +++ clang/test/Sema/overloadable-complex.c @@ -27,12 +27,12 @@ long *lp = foo(dc); } -char *promote_or_convert(double _Complex) __attribute__((__overloadable__)); // expected-note 2 {{candidate function}} -int *promote_or_convert(long double _Complex) __attribute__((__overloadable__)); // expected-note 2 {{candidate function}} +char *promote_or_convert(double _Complex) __attribute__((__overloadable__)); // expected-note {{candidate function}} +int *promote_or_convert(long double _Complex) __attribute__((__overloadable__)); // expected-note {{candidate function}} void test_promote_or_convert(float f, float _Complex fc) { - char *cp = promote_or_convert(fc); // expected-error{{call to 'promote_or_convert' is ambiguous}} - int *ip2 = promote_or_convert(f); // expected-error{{call to 'promote_or_convert' is ambiguous}} + char *cp = promote_or_convert(fc); + char *ip2 = promote_or_convert(f); // expected-error{{call to 'promote_or_convert' is ambiguous}} } char *promote_or_convert2(float) __attribute__((__overloadable__)); @@ -48,3 +48,11 @@ void test_promote_or_convert3(short _Complex sc) { char *cp = promote_or_convert3(sc); } + +char *promote_or_convert4(float _Complex) __attribute__((__overloadable__)); // expected-note 2 {{candidate function}} +int *promote_or_convert4(long double _Complex) __attribute__((__overloadable__)); // expected-note 2 {{candidate function}} + +void test_promote_or_convert4(double d, double _Complex dc) { + char *cp = promote_or_convert4(dc); // expected-error{{call to 'promote_or_convert4' is ambiguous}} + int *ip2 = promote_or_convert4(d); // expected-error{{call to 'promote_or_convert4' is ambiguous}} +} Index: clang/test/SemaCXX/floating-point-promotion.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/floating-point-promotion.cpp @@ -0,0 +1,110 @@ +// RUN: %clang_cc1 -fsyntax-only -fallow-half-arguments-and-returns -verify %s +// RUN: %clang_cc1 -fsyntax-only -fallow-half-arguments-and-returns -fnative-half-type -verify %s + +#include + +typedef __fp16 half; + +// expected-note@floating-point-promotion.cpp:* 1+ {{candidate function}} + +extern void half_to_int_or_float(int x); +extern void half_to_int_or_float(float x); +void test1(half h) { + half_to_int_or_float(h); // expected-error {{call to 'half_to_int_or_float' is ambiguous}} +} + +extern void half_to_int_or_double(int x); +extern void half_to_int_or_double(double x); +void test2(half h) { + half_to_int_or_double(h); +} + +extern void half_to_int_or_long_double(int x); +extern void half_to_int_or_long_double(long double x); +void test3(half h) { + half_to_int_or_long_double(h); // expected-error {{call to 'half_to_int_or_long_double' is ambiguous}} +} + +extern void half_to_float_or_double(float x); +extern void half_to_float_or_double(double x); +void test4(half h) { + half_to_float_or_double(h); +} + +extern void half_to_float_or_long_double(float x); +extern void half_to_float_or_long_double(long double x); +void test5(half h) { + half_to_float_or_long_double(h); // expected-error {{call to 'half_to_float_or_long_double' is ambiguous}} +} + +extern void float_to_int_or_half(int x); +extern void float_to_int_or_half(half x); +void test6(float f) { + float_to_int_or_half(f); // expected-error {{call to 'float_to_int_or_half' is ambiguous}} +} + +extern void float_to_int_or_double(int x); +extern void float_to_int_or_double(double x); +void test7(float f) { + float_to_int_or_double(f); +} + +extern void float_to_int_or_long_double(int x); +extern void float_to_int_or_long_double(long double x); +void test8(float f) { + float_to_int_or_long_double(f); // expected-error {{call to 'float_to_int_or_long_double' is ambiguous}} +} + +extern void float_to_half_or_double(half x); +extern void float_to_half_or_double(double x); +void test9(float f) { + float_to_half_or_double(f); +} + +extern void float_to_half_or_long_double(half x); +extern void float_to_half_or_long_double(long double x); +void test10(float f) { + float_to_half_or_long_double(f); // expected-error {{call to 'float_to_half_or_long_double' is ambiguous}} +} + +extern void double_to_int_or_half(int x); +extern void double_to_int_or_half(half x); +void test11(double d) { + double_to_int_or_half(d); // expected-error {{call to 'double_to_int_or_half' is ambiguous}} +} + +extern void double_to_int_or_float(int x); +extern void double_to_int_or_float(float x); +void test12(double d) { + double_to_int_or_float(d); // expected-error {{call to 'double_to_int_or_float' is ambiguous}} +} + +extern void double_to_int_or_long_double(int x); +extern void double_to_int_or_long_double(long double x); +void test13(double d) { + double_to_int_or_long_double(d); // expected-error {{call to 'double_to_int_or_long_double' is ambiguous}} +} + +extern void double_to_half_or_float(half x); +extern void double_to_half_or_float(float x); +void test14(double d) { + double_to_half_or_float(d); // expected-error {{call to 'double_to_half_or_float' is ambiguous}} +} + +extern void double_to_half_or_long_double(half x); +extern void double_to_half_or_long_double(long double x); +void test15(double d) { + double_to_half_or_long_double(d); // expected-error {{call to 'double_to_half_or_long_double' is ambiguous}} +} + +extern void long_double_to_half_or_float(half x); +extern void long_double_to_half_or_float(float x); +void test16(long double ld) { + double_to_half_or_float(ld); // expected-error {{call to 'double_to_half_or_float' is ambiguous}} +} + +extern void long_double_to_float_or_double(float x); +extern void long_double_to_float_or_double(double x); +void test17(long double ld) { + long_double_to_float_or_double(ld); // expected-error {{call to 'long_double_to_float_or_double' is ambiguous}} +}