r224205 - If a non-template constructor instantiated to X(X),

John McCall rjmccall at apple.com
Sat Dec 13 17:46:56 PST 2014


Author: rjmccall
Date: Sat Dec 13 19:46:53 2014
New Revision: 224205

URL: http://llvm.org/viewvc/llvm-project?rev=224205&view=rev
Log:
If a non-template constructor instantiated to X(X),
ignore it during overload resolution when initializing
X from a value of type cv X.

Previously, our rule here only ignored specializations
of constructor templates.  That's probably because the
standard says that constructors are outright ill-formed
if their first parameter is literally X and they're
callable with one argument.  However, Clang only
enforces that prohibition against non-implicit
instantiations; I'm not sure why, but it seems to be
deliberate.  Given that, the most sensible thing to
do is to just ignore the "illegal" constructor
regardless of where it came from.

Also, stop ignoring such constructors silently:
print a note explaining why they're being ignored.

Fixes <rdar://19199836>.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Overload.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/SemaTemplate/constructor-template.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=224205&r1=224204&r2=224205&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Dec 13 19:46:53 2014
@@ -2847,6 +2847,9 @@ def note_ovl_candidate : Note<"candidate
     "|volatile and restrict|const, volatile, and restrict}4)}2">;
 
 def note_ovl_candidate_inherited_constructor : Note<"inherited from here">;
+def note_ovl_candidate_illegal_constructor : Note<
+    "candidate %select{constructor|template}0 ignored: "
+    "instantiation %select{takes|would take}0 its own class type by value">;
 def note_ovl_candidate_bad_deduction : Note<
     "candidate template ignored: failed template argument deduction">;
 def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: "

Modified: cfe/trunk/include/clang/Sema/Overload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=224205&r1=224204&r2=224205&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Overload.h (original)
+++ cfe/trunk/include/clang/Sema/Overload.h Sat Dec 13 19:46:53 2014
@@ -553,6 +553,17 @@ namespace clang {
     /// conversion.
     ovl_fail_trivial_conversion,
 
+    /// This conversion candidate was not considered because it is
+    /// an illegal instantiation of a constructor temploid: it is
+    /// callable with one argument, we only have one argument, and
+    /// its first parameter type is exactly the type of the class.
+    ///
+    /// Defining such a constructor directly is illegal, and
+    /// template-argument deduction is supposed to ignore such
+    /// instantiations, but we can still get one with the right
+    /// kind of implicit instantiation.
+    ovl_fail_illegal_constructor,
+
     /// This conversion candidate is not viable because its result
     /// type is not implicitly convertible to the desired type.
     ovl_fail_bad_final_conversion,

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=224205&r1=224204&r2=224205&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Sat Dec 13 19:46:53 2014
@@ -1831,7 +1831,6 @@ bool CXXConstructorDecl::isConvertingCon
 bool CXXConstructorDecl::isSpecializationCopyingObject() const {
   if ((getNumParams() < 1) ||
       (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) ||
-      (getPrimaryTemplate() == nullptr) ||
       (getDescribedFunctionTemplate() != nullptr))
     return false;
 

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=224205&r1=224204&r2=224205&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Sat Dec 13 19:46:53 2014
@@ -5586,6 +5586,15 @@ Sema::AddOverloadCandidate(FunctionDecl
   // Overload resolution is always an unevaluated context.
   EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
 
+  // Add this candidate
+  OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size());
+  Candidate.FoundDecl = FoundDecl;
+  Candidate.Function = Function;
+  Candidate.Viable = true;
+  Candidate.IsSurrogate = false;
+  Candidate.IgnoreObjectArgument = false;
+  Candidate.ExplicitCallArguments = Args.size();
+
   if (Constructor) {
     // C++ [class.copy]p3:
     //   A member function template is never instantiated to perform the copy
@@ -5594,19 +5603,13 @@ Sema::AddOverloadCandidate(FunctionDecl
     if (Args.size() == 1 &&
         Constructor->isSpecializationCopyingObject() &&
         (Context.hasSameUnqualifiedType(ClassType, Args[0]->getType()) ||
-         IsDerivedFrom(Args[0]->getType(), ClassType)))
+         IsDerivedFrom(Args[0]->getType(), ClassType))) {
+      Candidate.Viable = false;
+      Candidate.FailureKind = ovl_fail_illegal_constructor;
       return;
+    }
   }
 
-  // Add this candidate
-  OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size());
-  Candidate.FoundDecl = FoundDecl;
-  Candidate.Function = Function;
-  Candidate.Viable = true;
-  Candidate.IsSurrogate = false;
-  Candidate.IgnoreObjectArgument = false;
-  Candidate.ExplicitCallArguments = Args.size();
-
   unsigned NumParams = Proto->getNumParams();
 
   // (C++ 13.3.2p2): A candidate function having fewer than m
@@ -9235,6 +9238,13 @@ static void NoteFunctionCandidate(Sema &
   case ovl_fail_bad_deduction:
     return DiagnoseBadDeduction(S, Cand, NumArgs);
 
+  case ovl_fail_illegal_constructor: {
+    S.Diag(Fn->getLocation(), diag::note_ovl_candidate_illegal_constructor)
+      << (Fn->getPrimaryTemplate() ? 1 : 0);
+    MaybeEmitInheritedConstructorNote(S, Fn);
+    return;
+  }
+
   case ovl_fail_trivial_conversion:
   case ovl_fail_bad_final_conversion:
   case ovl_fail_final_conversion_not_exact:

Modified: cfe/trunk/test/SemaTemplate/constructor-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/constructor-template.cpp?rev=224205&r1=224204&r2=224205&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/constructor-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/constructor-template.cpp Sat Dec 13 19:46:53 2014
@@ -54,7 +54,7 @@ struct B { A<int> x; B(B& a) : x(a.x) {}
 struct X2 {
   X2(); // expected-note{{candidate constructor}}
   X2(X2&);	// expected-note {{candidate constructor}}
-  template<typename T> X2(T);
+  template<typename T> X2(T); // expected-note {{candidate template ignored: instantiation would take its own class type by value}}
 };
 
 X2 test(bool Cond, X2 x2) {
@@ -126,3 +126,51 @@ namespace PR8182 {
   }
 
 }
+
+// Don't blow out the stack trying to call an illegal constructor
+// instantiation.  We intentionally allow implicit instantiations to
+// exist, so make sure they're unusable.
+//
+// rdar://19199836
+namespace self_by_value {
+  template <class T, class U> struct A {
+    A() {}
+    A(const A<T,U> &o) {}
+    A(A<T,T> o) {}
+  };
+
+  void helper(A<int,float>);
+
+  void test1(A<int,int> a) {
+    helper(a);
+  }
+  void test2() {
+    helper(A<int,int>());
+  }
+}
+
+namespace self_by_value_2 {
+  template <class T, class U> struct A {
+    A() {} // expected-note {{not viable: requires 0 arguments}}
+    A(A<T,U> &o) {} // expected-note {{not viable: expects an l-value}}
+    A(A<T,T> o) {} // expected-note {{ignored: instantiation takes its own class type by value}}
+  };
+
+  void helper_A(A<int,int>); // expected-note {{passing argument to parameter here}}
+  void test_A() {
+    helper_A(A<int,int>()); // expected-error {{no matching constructor}}
+  }
+}
+
+namespace self_by_value_3 {
+  template <class T, class U> struct A {
+    A() {}
+    A(A<T,U> &o) {}
+    A(A<T,T> o) {}
+  };
+
+  void helper_A(A<int,int>);
+  void test_A(A<int,int> b) {
+    helper_A(b);
+  }
+}





More information about the cfe-commits mailing list