From: Douglas Gregor Date: Wed, 12 Oct 2011 20:35:48 +0000 (+0000) Subject: When we determine that a function template specialization produced as X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5fad9b8362c62e230f6603d86ec7d1747e74c737;p=clang When we determine that a function template specialization produced as part of template argument deduction is ill-formed, we mark it as invalid and treat it as a deduction failure. If we happen to find that specialization again, treat it as a deduction failure rather than silently building a call to the declaration. Fixes PR11117, a marvelous bug where deduction failed after creating an invalid specialization, causing overload resolution to pick a different candidate. Then we performed a similar overload resolution later, and happily picked the invalid specialization to call... resulting in a silent link failure. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141809 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 03850bb760..93ea89d628 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -2589,7 +2589,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, Specialization = cast_or_null( SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, MultiLevelTemplateArgumentList(*DeducedArgumentList))); - if (!Specialization) + if (!Specialization || Specialization->isInvalidDecl()) return TDK_SubstitutionFailure; assert(Specialization->getPrimaryTemplate()->getCanonicalDecl() == @@ -2601,6 +2601,14 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, !Trap.hasErrorOccurred()) Info.take(); + // There may have been an error that did not prevent us from constructing a + // declaration. Mark the declaration invalid and return with a substitution + // failure. + if (Trap.hasErrorOccurred()) { + Specialization->setInvalidDecl(true); + return TDK_SubstitutionFailure; + } + if (OriginalCallArgs) { // C++ [temp.deduct.call]p4: // In general, the deduction process attempts to find template argument @@ -2619,14 +2627,6 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, } } - // There may have been an error that did not prevent us from constructing a - // declaration. Mark the declaration invalid and return with a substitution - // failure. - if (Trap.hasErrorOccurred()) { - Specialization->setInvalidDecl(true); - return TDK_SubstitutionFailure; - } - // If we suppressed any diagnostics while performing template argument // deduction, and if we haven't already instantiated this declaration, // keep track of these diagnostics. They'll be emitted if this specialization diff --git a/test/CXX/temp/temp.decls/temp.mem/p5.cpp b/test/CXX/temp/temp.decls/temp.mem/p5.cpp index a188f05d53..8bcd773ee9 100644 --- a/test/CXX/temp/temp.decls/temp.mem/p5.cpp +++ b/test/CXX/temp/temp.decls/temp.mem/p5.cpp @@ -63,7 +63,8 @@ struct X0 { template operator const T*() const { T x = T(); - return x; // expected-error{{cannot initialize return object of type 'const char *' with an lvalue of type 'char'}} + return x; // expected-error{{cannot initialize return object of type 'const char *' with an lvalue of type 'char'}} \ + // expected-error{{cannot initialize return object of type 'const int *' with an lvalue of type 'int'}} } }; @@ -72,7 +73,7 @@ template X0::operator const int*(); // expected-note{{'X0::operator const int *< template X0::operator float*() const; // expected-error{{explicit instantiation of undefined function template}} void test_X0(X0 x0, const X0 &x0c) { - x0.operator const int*(); + x0.operator const int*(); // expected-note{{in instantiation of function template specialization}} x0.operator float *(); x0c.operator const char*(); } diff --git a/test/SemaTemplate/operator-template.cpp b/test/SemaTemplate/operator-template.cpp index 4300755cf7..777b0f5f42 100644 --- a/test/SemaTemplate/operator-template.cpp +++ b/test/SemaTemplate/operator-template.cpp @@ -2,7 +2,8 @@ // Make sure we accept this templatestruct A{typedef X Y;}; -templatebool operator==(A,typename A::Y); +templatebool operator==(A,typename A::Y); // expected-note{{candidate template ignored: failed template argument deduction}} + int a(A x) { return operator==(x,1); } int a0(A x) { return x == 1; } @@ -10,7 +11,8 @@ int a0(A x) { return x == 1; } // FIXME: the location information for the note isn't very good templatestruct B{typedef X Y;}; templatebool operator==(B*,typename B::Y); // \ -expected-error{{overloaded 'operator==' must have at least one parameter of class or enumeration type}} \ -expected-note{{in instantiation of function template specialization}} -int a(B x) { return operator==(&x,1); } +// expected-error{{overloaded 'operator==' must have at least one parameter of class or enumeration type}} \ +// expected-note{{in instantiation of function template specialization}} \ +// expected-note{{candidate template ignored: substitution failure [with X = int]}} +int a(B x) { return operator==(&x,1); } // expected-error{{no matching function for call to 'operator=='}} diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp index 43fe38ba7c..747ddcc461 100644 --- a/test/SemaTemplate/temp_arg_nontype.cpp +++ b/test/SemaTemplate/temp_arg_nontype.cpp @@ -170,7 +170,7 @@ namespace pr6249 { namespace PR6723 { template void f(int (&a)[C]); // expected-note {{candidate template ignored}} \ - // expected-note{{candidate function [with C = '\x00'] not viable: no known conversion from 'int [512]' to 'int (&)[0]' for 1st argument}} + // expected-note{{substitution failure [with C = '\x00']}} void g() { int arr512[512]; f(arr512); // expected-error{{no matching function for call}}