]> granicus.if.org Git - clang/commitdiff
Introduce _Complex conversions into the function overloading
authorDouglas Gregor <dgregor@apple.com>
Thu, 12 Feb 2009 00:15:05 +0000 (00:15 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 12 Feb 2009 00:15:05 +0000 (00:15 +0000)
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
lib/Sema/Sema.h
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaOverload.h
test/SemaCXX/complex-overload.cpp [new file with mode: 0644]

index d844d6c6bb0aaa09818086181cd6f07d6a390a8f..24cf8535556a6466caff53d22add6d2833bb3036 100644 (file)
@@ -82,6 +82,10 @@ QualType Type::getDesugaredType() const {
     return TOE->getUnderlyingExpr()->getType();
   if (const TypeOfType *TOT = dyn_cast<TypeOfType>(this))
     return TOT->getUnderlyingType();
+  if (const ClassTemplateSpecializationType *Spec 
+        = dyn_cast<ClassTemplateSpecializationType>(this))
+    return Spec->getCanonicalTypeInternal();
+
   // FIXME: remove this cast.
   return QualType(const_cast<Type*>(this), 0);
 }
index aafddc5a03835d761978c47935de54ed86518b94..a0fa0c7f3dab512be6d9814867f8dcdbee84ccdc 100644 (file)
@@ -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,
index 6ce83315553c26b6c2a6533b9c84049c62ee84e4..9f494d98593ef8d631394b3bffedec241c9d4c19 100644 (file)
@@ -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();
index e1939d329e923e9f106010565599c3295b6ad971..48d31056a7928555e85604cbabd728607b4f65a6 100644 (file)
@@ -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,
index 2511c2d6ead04c1b715bdf08c8c645b211f427df..3da8eca1a5a9f480f091c2b11f0ffde979638af9 100644 (file)
@@ -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 (file)
index 0000000..4d27a20
--- /dev/null
@@ -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);
+}