summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--include/clang/Sema/Overload.h11
-rw-r--r--lib/AST/DeclCXX.cpp1
-rw-r--r--lib/Sema/SemaOverload.cpp30
-rw-r--r--test/SemaTemplate/constructor-template.cpp50
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);
+ }
+}