]> granicus.if.org Git - clang/commitdiff
Issue good diagnostics when initialization failes due to
authorFariborz Jahanian <fjahanian@apple.com>
Tue, 15 Sep 2009 19:12:21 +0000 (19:12 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Tue, 15 Sep 2009 19:12:21 +0000 (19:12 +0000)
ambiguity in type conversion function selection.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81898 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/Sema.h
lib/Sema/SemaInit.cpp
lib/Sema/SemaOverload.cpp
test/SemaCXX/deleted-function.cpp
test/SemaCXX/direct-initializer.cpp

index 109bb4d08bf9d6e00da4f2d71c29f8800f84300e..6a8ad5c6177e00354def33106d8f7f8edfa3e380 100644 (file)
@@ -1643,6 +1643,8 @@ def warn_value_always_false : Warning<"%0 is always false in this context">;
 // FIXME: %2 is an english string here.
 def err_typecheck_convert_incompatible : Error<
   "incompatible type %2 %1, expected %0">;
+def err_typecheck_convert_ambiguous : Error<
+  "ambiguity in initializing value of type %0 with initializer of type %1">;
 def err_cannot_initialize_decl_noname : Error<
   "cannot initialize a value of type %0 with an %select{rvalue|lvalue}1 "
   "of type %2">;
index 2713f7a9553e9aa76a176abcf7f51fd675fa93bb..84e73a6fecf8d89711a1f383b22e1e047d101a87 100644 (file)
@@ -734,6 +734,15 @@ public:
     return NULL;
   }
 
+  /// OverloadingResult - Capture the result of performing overload
+  /// resolution.
+  enum OverloadingResult {
+    OR_Success,             ///< Overload resolution succeeded.
+    OR_No_Viable_Function,  ///< No viable function found.
+    OR_Ambiguous,           ///< Ambiguous candidates found.
+    OR_Deleted              ///< Overload resoltuion refers to a deleted function.
+  };
+
 
   /// Subroutines of ActOnDeclarator().
   TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T);
@@ -770,7 +779,7 @@ public:
   bool CheckMemberPointerConversion(Expr *From, QualType ToType,
                                     CastExpr::CastKind &Kind);
   bool IsQualificationConversion(QualType FromType, QualType ToType);
-  bool IsUserDefinedConversion(Expr *From, QualType ToType,
+  OverloadingResult IsUserDefinedConversion(Expr *From, QualType ToType,
                                UserDefinedConversionSequence& User,
                                OverloadCandidateSet& Conversions,
                                bool AllowConversionFunctions,
@@ -808,15 +817,6 @@ public:
 
   bool PerformObjectMemberConversion(Expr *&From, NamedDecl *Member);
 
-  /// OverloadingResult - Capture the result of performing overload
-  /// resolution.
-  enum OverloadingResult {
-    OR_Success,             ///< Overload resolution succeeded.
-    OR_No_Viable_Function,  ///< No viable function found.
-    OR_Ambiguous,           ///< Ambiguous candidates found.
-    OR_Deleted              ///< Overload resoltuion refers to a deleted function.
-  };
-
   // Members have to be NamespaceDecl* or TranslationUnitDecl*.
   // TODO: make this is a typesafe union.
   typedef llvm::SmallPtrSet<DeclContext   *, 16> AssociatedNamespaceSet;
index 328609a1929b453a9c8bffaf40041e9d99880273..6574524d14d0d67df2416d9346e2a9c491c2f89e 100644 (file)
@@ -70,11 +70,23 @@ static bool CheckSingleInitializer(Expr *&Init, QualType DeclType,
 
   if (S.getLangOptions().CPlusPlus) {
     // FIXME: I dislike this error message. A lot.
-    if (S.PerformImplicitConversion(Init, DeclType, "initializing", DirectInit))
-      return S.Diag(Init->getSourceRange().getBegin(),
-                    diag::err_typecheck_convert_incompatible)
-        << DeclType << Init->getType() << "initializing"
-        << Init->getSourceRange();
+    if (S.PerformImplicitConversion(Init, DeclType, 
+                                    "initializing", DirectInit)) {
+      ImplicitConversionSequence ICS;
+      OverloadCandidateSet CandidateSet;
+      if (S.IsUserDefinedConversion(Init, DeclType, ICS.UserDefined,
+                              CandidateSet,
+                              true, false, false) != S.OR_Ambiguous)
+        return S.Diag(Init->getSourceRange().getBegin(),
+                      diag::err_typecheck_convert_incompatible)
+                      << DeclType << Init->getType() << "initializing"
+                      << Init->getSourceRange();
+      S.Diag(Init->getSourceRange().getBegin(),
+             diag::err_typecheck_convert_ambiguous)
+            << DeclType << Init->getType() << Init->getSourceRange();
+      S.PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+      return true;
+    }
     return false;
   }
 
index d406dd47c7b946d8ffd65bf5285b08e4b1005ce4..cda7c829689746a4011e7ed94152a8d740a2c497 100644 (file)
@@ -417,7 +417,7 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
            IsUserDefinedConversion(From, ToType, ICS.UserDefined,
                                    Conversions,
                                    !SuppressUserConversions, AllowExplicit,
-                                   ForceRValue)) {
+                                   ForceRValue) == OR_Success) {
     ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
     // C++ [over.ics.user]p4:
     //   A conversion of an expression of class type to the same class
@@ -1355,7 +1355,8 @@ static void GetFunctionAndTemplate(AnyFunctionDecl Orig, T *&Function,
 ///
 /// \param ForceRValue  true if the expression should be treated as an rvalue
 /// for overload resolution.
-bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
+Sema::OverloadingResult Sema::IsUserDefinedConversion(
+                                   Expr *From, QualType ToType,
                                    UserDefinedConversionSequence& User,
                                    OverloadCandidateSet& CandidateSet,
                                    bool AllowConversionFunctions,
@@ -1458,7 +1459,7 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
         User.After.FromTypePtr
           = ThisType->getAs<PointerType>()->getPointeeType().getAsOpaquePtr();
         User.After.ToTypePtr = ToType.getAsOpaquePtr();
-        return true;
+        return OR_Success;
       } else if (CXXConversionDecl *Conversion
                    = dyn_cast<CXXConversionDecl>(Best->Function)) {
         // C++ [over.ics.user]p1:
@@ -1480,24 +1481,25 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
         //   user-defined conversion sequence (see 13.3.3 and
         //   13.3.3.1).
         User.After = Best->FinalConversion;
-        return true;
+        return OR_Success;
       } else {
         assert(false && "Not a constructor or conversion function?");
-        return false;
+        return OR_No_Viable_Function;
       }
 
     case OR_No_Viable_Function:
+      return OR_No_Viable_Function;
     case OR_Deleted:
       // No conversion here! We're done.
-      return false;
+      return OR_Deleted;
 
     case OR_Ambiguous:
       // FIXME: See C++ [over.best.ics]p10 for the handling of
       // ambiguous conversion sequences.
-      return false;
+      return OR_Ambiguous;
     }
 
-  return false;
+  return OR_No_Viable_Function;
 }
 
 /// CompareImplicitConversionSequences - Compare two implicit
@@ -2100,10 +2102,9 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
     return false;
 
     OverloadCandidateSet CandidateSet;
-    IsUserDefinedConversion(From, Context.BoolTy, ICS.UserDefined,
+    if (IsUserDefinedConversion(From, Context.BoolTy, ICS.UserDefined,
                             CandidateSet,
-                            true, true, false);
-    if (CandidateSet.begin() == CandidateSet.end())
+                            true, true, false) != OR_Ambiguous)
       return  Diag(From->getSourceRange().getBegin(),
                    diag::err_typecheck_bool_condition)
                     << From->getType() << From->getSourceRange();
index 8064ed349b084b1ab83da6312f81dc13d4d8f051..637b2b1b2d5c9556cc404c7436fba9473c920857 100644 (file)
@@ -18,7 +18,7 @@ void ov(double) = delete; // expected-note {{candidate function has been explici
 struct WithDel {
   WithDel() = delete; // expected-note {{candidate function has been explicitly deleted}}
   void fn() = delete; // expected-note {{function has been explicitly marked deleted here}}
-  operator int() = delete;
+  operator int() = delete; 
   void operator +(int) = delete;
 
   int i = delete; // expected-error {{only functions can have deleted definitions}}
index 149b65c8d71d3fe3b778347018f37d6acf41f38e..e95ba227690f0b2c30708c9dcfeeb81c39541069 100644 (file)
@@ -34,3 +34,17 @@ void g() {
 
   Z z; // expected-error{{no matching constructor for initialization of 'z'}}
 }
+
+struct Base {
+   operator int*() const; // expected-note {{candidate function}}
+};
+
+struct Derived : Base {
+   operator int*(); // expected-note {{candidate function}}
+};
+
+void foo(const Derived cd, Derived d) {
+        int *pi = cd;
+        int *ppi = d; // expected-error {{ambiguity in initializing value of type 'int *' with initializer of type 'struct Derived'}}
+
+}