diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 6 | ||||
-rw-r--r-- | clang/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp | 39 |
2 files changed, 35 insertions, 10 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 267eea8a1bc..9163aba9f5b 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2852,9 +2852,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) { // An out-of-line member function declaration must also be a // definition (C++ [dcl.meaning]p1). - // FIXME: Find a better way to recognize out-of-line specializations! + // Note that this is not the case for explicit specializations of + // function templates or member functions of class templates, per + // C++ [temp.expl.spec]p2. if (!IsFunctionDefinition && !isFriend && - !(TemplateParamLists.size() && !FunctionTemplate)) { + NewFD->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) { Diag(NewFD->getLocation(), diag::err_out_of_line_declaration) << D.getCXXScopeSpec().getRange(); NewFD->setInvalidDecl(); diff --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp index 9c6c5edc504..64856605a0a 100644 --- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp +++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp @@ -62,7 +62,7 @@ struct X0 { // expected-note 2{{here}} // expected-error{{base specifier}} template<typename U> - void ft1(T t, U u); + void ft1(T t, U u); // expected-note{{explicitly specialized}} }; } @@ -203,14 +203,37 @@ N0::X0<int>::InnerTemplate<int> inner_template1; // expected-error{{incomplete}} N0::X0<int>::InnerTemplate<long> inner_template2; N0::X0<int>::InnerTemplate<unsigned long> inner_template3; // expected-note{{instantiation}} -#if 0 -// FIXME: update the remainder of this test to check for scopes properly. // -- member function template of a class template -template<> -template<> -void X0<void*>::ft1(void*, const void*) { } +namespace N0 { + template<> + template<> + void X0<void*>::ft1(void*, const void*) { } + + template<> template<> + void X0<void*>::ft1(void *, int); + + template<> template<> + void X0<void*>::ft1(void *, unsigned); + + template<> template<> + void X0<void*>::ft1(void *, long); +} + +template<> template<> +void N0::X0<void*>::ft1(void *, unsigned) { } // okay + +template<> template<> +void N0::X0<void*>::ft1(void *, float) { } // expected-error{{function template specialization}} + +namespace N1 { + template<> template<> + void N0::X0<void*>::ft1(void *, long) { } // expected-error{{enclosing}} +} + -void test_func_template(X0<void *> xvp, void *vp, const void *cvp) { +void test_func_template(N0::X0<void *> xvp, void *vp, const void *cvp, + int i, unsigned u) { xvp.ft1(vp, cvp); + xvp.ft1(vp, i); + xvp.ft1(vp, u); } -#endif |