From 5cdf82164dd7c2b2320d6735c63ace4331e0716d Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 12 Feb 2009 00:15:05 +0000 Subject: [PATCH] Introduce _Complex conversions into the function overloading system. Since C99 doesn't have overloading and C++ doesn't have _Complex, there is no specification for this. Here's what I think makes sense. Complex conversions come in several flavors: - Complex promotions: a complex -> complex conversion where the underlying real-type conversion is a floating-point promotion. GCC seems to call this a promotion, EDG does something else. This is given "promotion" rank for determining the best viable function. - Complex conversions: a complex -> complex conversion that is not a complex promotion. This is given "conversion" rank for determining the best viable function. - Complex-real conversions: a real -> complex or complex -> real conversion. This is given "conversion" rank for determining the best viable function. These rules are the same for C99 (when using the "overloadable" attribute) and C++. However, there is one difference in the handling of floating-point promotions: in C99, float -> long double and double -> long double are considered promotions (so we give them "promotion" rank), while C++ considers these conversions ("conversion" rank). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64343 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/Type.cpp | 4 +++ lib/Sema/Sema.h | 1 + lib/Sema/SemaExprCXX.cpp | 3 ++ lib/Sema/SemaOverload.cpp | 55 ++++++++++++++++++++++++++++++- lib/Sema/SemaOverload.h | 3 ++ test/SemaCXX/complex-overload.cpp | 43 ++++++++++++++++++++++++ 6 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 test/SemaCXX/complex-overload.cpp diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index d844d6c6bb..24cf853555 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -82,6 +82,10 @@ QualType Type::getDesugaredType() const { return TOE->getUnderlyingExpr()->getType(); if (const TypeOfType *TOT = dyn_cast(this)) return TOT->getUnderlyingType(); + if (const ClassTemplateSpecializationType *Spec + = dyn_cast(this)) + return Spec->getCanonicalTypeInternal(); + // FIXME: remove this cast. return QualType(const_cast(this), 0); } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index aafddc5a03..a0fa0c7f3d 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -424,6 +424,7 @@ public: StandardConversionSequence& SCS); bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType); bool IsFloatingPointPromotion(QualType FromType, QualType ToType); + bool IsComplexPromotion(QualType FromType, QualType ToType); bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType, QualType& ConvertedType, bool &IncompatibleObjC); bool isObjCPointerConversion(QualType FromType, QualType ToType, diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 6ce8331555..9f494d9859 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -806,9 +806,12 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, case ICK_Integral_Promotion: case ICK_Floating_Promotion: + case ICK_Complex_Promotion: case ICK_Integral_Conversion: case ICK_Floating_Conversion: + case ICK_Complex_Conversion: case ICK_Floating_Integral: + case ICK_Complex_Real: case ICK_Compatible_Conversion: // FIXME: Go deeper to get the unqualified type! FromType = ToType.getUnqualifiedType(); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index e1939d329e..48d31056a7 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -39,6 +39,9 @@ GetConversionCategory(ImplicitConversionKind Kind) { ICC_Qualification_Adjustment, ICC_Promotion, ICC_Promotion, + ICC_Promotion, + ICC_Conversion, + ICC_Conversion, ICC_Conversion, ICC_Conversion, ICC_Conversion, @@ -63,6 +66,9 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) { ICR_Exact_Match, ICR_Promotion, ICR_Promotion, + ICR_Promotion, + ICR_Conversion, + ICR_Conversion, ICR_Conversion, ICR_Conversion, ICR_Conversion, @@ -86,9 +92,12 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) { "Qualification", "Integral promotion", "Floating point promotion", + "Complex promotion", "Integral conversion", "Floating conversion", + "Complex conversion", "Floating-integral conversion", + "Complex-real conversion", "Pointer conversion", "Pointer-to-member conversion", "Boolean conversion", @@ -552,6 +561,11 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, SCS.Second = ICK_Floating_Promotion; FromType = ToType.getUnqualifiedType(); } + // Complex promotion (Clang extension) + else if (IsComplexPromotion(FromType, ToType)) { + SCS.Second = ICK_Complex_Promotion; + FromType = ToType.getUnqualifiedType(); + } // Integral conversions (C++ 4.7). // FIXME: isIntegralType shouldn't be true for enums in C++. else if ((FromType->isIntegralType() || FromType->isEnumeralType()) && @@ -564,6 +578,11 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, SCS.Second = ICK_Floating_Conversion; FromType = ToType.getUnqualifiedType(); } + // Complex conversions (C99 6.3.1.6) + else if (FromType->isComplexType() && ToType->isComplexType()) { + SCS.Second = ICK_Complex_Conversion; + FromType = ToType.getUnqualifiedType(); + } // Floating-integral conversions (C++ 4.9). // FIXME: isIntegralType shouldn't be true for enums in C++. else if ((FromType->isFloatingType() && @@ -574,6 +593,12 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, SCS.Second = ICK_Floating_Integral; FromType = ToType.getUnqualifiedType(); } + // Complex-real conversions (C99 6.3.1.7) + else if ((FromType->isComplexType() && ToType->isArithmeticType()) || + (ToType->isComplexType() && FromType->isArithmeticType())) { + SCS.Second = ICK_Complex_Real; + FromType = ToType.getUnqualifiedType(); + } // Pointer conversions (C++ 4.10). else if (IsPointerConversion(From, FromType, ToType, FromType, IncompatibleObjC)) { @@ -756,14 +781,42 @@ bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) /// An rvalue of type float can be converted to an rvalue of type /// double. (C++ 4.6p1). if (const BuiltinType *FromBuiltin = FromType->getAsBuiltinType()) - if (const BuiltinType *ToBuiltin = ToType->getAsBuiltinType()) + if (const BuiltinType *ToBuiltin = ToType->getAsBuiltinType()) { if (FromBuiltin->getKind() == BuiltinType::Float && 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 (!getLangOptions().CPlusPlus && + (FromBuiltin->getKind() == BuiltinType::Float || + FromBuiltin->getKind() == BuiltinType::Double) && + (ToBuiltin->getKind() == BuiltinType::LongDouble)) + return true; + } + return false; } +/// \brief Determine if a conversion is a complex promotion. +/// +/// A complex promotion is defined as a complex -> complex conversion +/// where the conversion between the underlying real types is a +/// floating-point conversion. +bool Sema::IsComplexPromotion(QualType FromType, QualType ToType) { + const ComplexType *FromComplex = FromType->getAsComplexType(); + if (!FromComplex) + return false; + + const ComplexType *ToComplex = ToType->getAsComplexType(); + if (!ToComplex) + return false; + + return IsFloatingPointPromotion(FromComplex->getElementType(), + ToComplex->getElementType()); +} + /// BuildSimilarlyQualifiedPointerType - In a pointer conversion from /// the pointer type FromPtr to a pointer to type ToPointee, with the /// same type qualifiers as FromPtr has on its pointee type. ToType, diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 2511c2d6ea..3da8eca1a5 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -33,9 +33,12 @@ namespace clang { ICK_Qualification, ///< Qualification conversions (C++ 4.4) ICK_Integral_Promotion, ///< Integral promotions (C++ 4.5) ICK_Floating_Promotion, ///< Floating point promotions (C++ 4.6) + ICK_Complex_Promotion, ///< Complex promotions (Clang extension) ICK_Integral_Conversion, ///< Integral conversions (C++ 4.7) ICK_Floating_Conversion, ///< Floating point conversions (C++ 4.8) + ICK_Complex_Conversion, ///< Complex conversions (C99 6.3.1.6) ICK_Floating_Integral, ///< Floating-integral conversions (C++ 4.9) + ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7) ICK_Pointer_Conversion, ///< Pointer conversions (C++ 4.10) ICK_Pointer_Member, ///< Pointer-to-member conversions (C++ 4.11) ICK_Boolean_Conversion, ///< Boolean conversions (C++ 4.12) diff --git a/test/SemaCXX/complex-overload.cpp b/test/SemaCXX/complex-overload.cpp new file mode 100644 index 0000000000..4d27a207ce --- /dev/null +++ b/test/SemaCXX/complex-overload.cpp @@ -0,0 +1,43 @@ +// RUN: clang -fsyntax-only -verify %s +char *foo(float); // expected-note 3 {{candidate function}} + +void test_foo_1(float fv, double dv, float _Complex fc, double _Complex dc) { + char *cp1 = foo(fv); + char *cp2 = foo(dv); + // Note: GCC and EDG reject these two, but they are valid C99 conversions + char *cp3 = foo(fc); + char *cp4 = foo(dc); +} + +int *foo(float _Complex); // expected-note 3 {{candidate function}} + +void test_foo_2(float fv, double dv, float _Complex fc, double _Complex dc) { + char *cp1 = foo(fv); + char *cp2 = foo(dv); // expected-error{{call to 'foo' is ambiguous; candidates are:}} + int *ip = foo(fc); + int *lp = foo(dc); // expected-error{{call to 'foo' is ambiguous; candidates are:}} +} + +long *foo(double _Complex); // expected-note {{candidate function}} + +void test_foo_3(float fv, double dv, float _Complex fc, double _Complex dc) { + char *cp1 = foo(fv); + char *cp2 = foo(dv); // expected-error{{call to 'foo' is ambiguous; candidates are:}} + int *ip = foo(fc); + long *lp = foo(dc); +} + +char *promote_or_convert(double _Complex); // expected-note{{candidate function}} +int *promote_or_convert(long double _Complex); // expected-note{{candidate function}} + +void test_promote_or_convert(float f, float _Complex fc) { + char *cp = promote_or_convert(fc); + int *ip2 = promote_or_convert(f); // expected-error{{call to 'promote_or_convert' is ambiguous; candidates are:}} +} + +char *promote_or_convert2(float); +int *promote_or_convert2(double _Complex); + +void test_promote_or_convert(float _Complex fc) { + int *cp = promote_or_convert2(fc); +} -- 2.40.0