diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | include/clang/Sema/Overload.h | 11 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 30 | ||||
-rw-r--r-- | test/SemaTemplate/constructor-template.cpp | 50 |
5 files changed, 83 insertions, 12 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 48fdf6f826..32bf1b067b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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: " diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h index 41dcf974e5..4447db2b3e 100644 --- a/include/clang/Sema/Overload.h +++ b/include/clang/Sema/Overload.h @@ -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, diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 0ee3e3e904..a6d9d411ee 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -1831,7 +1831,6 @@ bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const { bool CXXConstructorDecl::isSpecializationCopyingObject() const { if ((getNumParams() < 1) || (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) || - (getPrimaryTemplate() == nullptr) || (getDescribedFunctionTemplate() != nullptr)) return false; diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index d33f126db1..9058fc098d 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -5586,6 +5586,15 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // 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 *Function, 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 &S, OverloadCandidate *Cand, 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: diff --git a/test/SemaTemplate/constructor-template.cpp b/test/SemaTemplate/constructor-template.cpp index cf3fdfb7c1..c5306a6e32 100644 --- a/test/SemaTemplate/constructor-template.cpp +++ b/test/SemaTemplate/constructor-template.cpp @@ -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); + } +} |