From: Richard Smith Date: Tue, 18 Oct 2011 02:28:33 +0000 (+0000) Subject: Refactor the checking for explicit template instantiations being performed in X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3e2e91e934ecf083a7c0835b58d9627ca2faddc9;p=clang Refactor the checking for explicit template instantiations being performed in the right namespace in C++11 mode. Teach the code to prefer the 'must be in precisely this namespace' diagnostic whenever that's true, and fix a defect which resulted in the -Wc++11-compat warning in C++98 mode sometimes being omitted. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142329 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index f66019b76f..bc3740b49e 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2434,9 +2434,9 @@ def ext_explicit_instantiation_without_qualified_id : Extension< "qualifier in explicit instantiation of %q0 requires a template-id " "(a typedef is not permitted)">; def err_explicit_instantiation_unqualified_wrong_namespace : Error< - "explicit instantiation of %q0 must occur in %1">; + "explicit instantiation of %q0 must occur in namespace %1">; def warn_explicit_instantiation_unqualified_wrong_namespace_0x : Warning< - "explicit instantiation of %q0 must occur in %1">, + "explicit instantiation of %q0 must occur in namespace %1">, InGroup; def err_explicit_instantiation_undefined_member : Error< "explicit instantiation of undefined %select{member class|member function|" diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 8dda34c8ab..82a88312d7 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -5728,45 +5728,41 @@ static bool CheckExplicitInstantiationScope(Sema &S, NamedDecl *D, return true; } - // C++0x [temp.explicit]p2: + // C++11 [temp.explicit]p3: // An explicit instantiation shall appear in an enclosing namespace of its - // template. + // template. If the name declared in the explicit instantiation is an + // unqualified name, the explicit instantiation shall appear in the + // namespace where its template is declared or, if that namespace is inline + // (7.3.1), any namespace from its enclosing namespace set. // // This is DR275, which we do not retroactively apply to C++98/03. - if (S.getLangOptions().CPlusPlus0x && - !CurContext->Encloses(OrigContext)) { - if (NamespaceDecl *NS = dyn_cast(OrigContext)) + if (WasQualifiedName) { + if (CurContext->Encloses(OrigContext)) + return false; + } else { + if (CurContext->InEnclosingNamespaceSetOf(OrigContext)) + return false; + } + + if (NamespaceDecl *NS = dyn_cast(OrigContext)) { + if (WasQualifiedName) S.Diag(InstLoc, S.getLangOptions().CPlusPlus0x? - diag::err_explicit_instantiation_out_of_scope - : diag::warn_explicit_instantiation_out_of_scope_0x) + diag::err_explicit_instantiation_out_of_scope : + diag::warn_explicit_instantiation_out_of_scope_0x) << D << NS; else S.Diag(InstLoc, S.getLangOptions().CPlusPlus0x? - diag::err_explicit_instantiation_must_be_global - : diag::warn_explicit_instantiation_out_of_scope_0x) - << D; - S.Diag(D->getLocation(), diag::note_explicit_instantiation_here); - return false; - } - - // C++0x [temp.explicit]p2: - // If the name declared in the explicit instantiation is an unqualified - // name, the explicit instantiation shall appear in the namespace where - // its template is declared or, if that namespace is inline (7.3.1), any - // namespace from its enclosing namespace set. - if (WasQualifiedName) - return false; - - if (CurContext->InEnclosingNamespaceSetOf(OrigContext)) - return false; - - S.Diag(InstLoc, - S.getLangOptions().CPlusPlus0x? - diag::err_explicit_instantiation_unqualified_wrong_namespace - : diag::warn_explicit_instantiation_unqualified_wrong_namespace_0x) - << D << OrigContext; + diag::err_explicit_instantiation_unqualified_wrong_namespace : + diag::warn_explicit_instantiation_unqualified_wrong_namespace_0x) + << D << NS; + } else + S.Diag(InstLoc, + S.getLangOptions().CPlusPlus0x? + diag::err_explicit_instantiation_must_be_global : + diag::warn_explicit_instantiation_must_be_global_0x) + << D; S.Diag(D->getLocation(), diag::note_explicit_instantiation_here); return false; } @@ -5776,7 +5772,7 @@ static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) { if (!SS.isSet()) return false; - // C++0x [temp.explicit]p2: + // C++11 [temp.explicit]p3: // If the explicit instantiation is for a member function, a member class // or a static data member of a class template specialization, the name of // the class template specialization in the qualified-id for the member diff --git a/test/SemaCXX/cxx0x-compat.cpp b/test/SemaCXX/cxx0x-compat.cpp index a01b26c5f9..4a7c1defee 100644 --- a/test/SemaCXX/cxx0x-compat.cpp +++ b/test/SemaCXX/cxx0x-compat.cpp @@ -1,18 +1,21 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++98 -Wc++0x-compat -verify %s namespace N { - template void f(T) {} // expected-note {{here}} + template void f(T) {} // expected-note 2{{here}} namespace M { - template void f(int); // expected-warning {{explicit instantiation of 'N::f' must occur in namespace 'N'}} + template void ::N::f(int); // expected-warning {{explicit instantiation of 'f' not in a namespace enclosing 'N'}} } } +using namespace N; +template void f(char); // expected-warning {{explicit instantiation of 'N::f' must occur in namespace 'N'}} -template void f(T) {} // expected-note {{here}} +template void g(T) {} // expected-note 2{{here}} namespace M { - template void f(int); // expected-warning {{explicit instantiation of 'f' must occur in the global namespace}} + template void g(int); // expected-warning {{explicit instantiation of 'g' must occur at global scope}} + template void ::g(char); // expected-warning {{explicit instantiation of 'g' must occur at global scope}} } -void f() { +void g() { auto int n = 0; // expected-warning {{'auto' storage class specifier is redundant and incompatible with C++11}} } diff --git a/test/SemaTemplate/temp_explicit.cpp b/test/SemaTemplate/temp_explicit.cpp index 76244c25e8..8a56d724ea 100644 --- a/test/SemaTemplate/temp_explicit.cpp +++ b/test/SemaTemplate/temp_explicit.cpp @@ -80,7 +80,7 @@ struct X5 { void f(T&); }; - struct Inner2 { + struct Inner2 { // expected-note {{here}} struct VeryInner { void g(T*); // expected-error 2{{pointer to a reference}} }; @@ -98,7 +98,7 @@ void f4(X5::Inner2); template struct X5::Inner2; // expected-note{{instantiation}} namespace N3 { - template struct N2::X5::Inner2; + template struct N2::X5::Inner2; // expected-warning {{explicit instantiation of 'Inner2' not in a namespace enclosing 'N2'}} } struct X6 { @@ -147,5 +147,5 @@ namespace N2 { template struct X7; // expected-warning{{must occur in namespace}} - template struct X9; // expected-warning{{must occur in the global}} + template struct X9; // expected-warning{{must occur at global scope}} } diff --git a/test/SemaTemplate/temp_explicit_cxx0x.cpp b/test/SemaTemplate/temp_explicit_cxx0x.cpp index 9d6dc80b5b..e37fcd7c6a 100644 --- a/test/SemaTemplate/temp_explicit_cxx0x.cpp +++ b/test/SemaTemplate/temp_explicit_cxx0x.cpp @@ -18,7 +18,7 @@ template struct ::N1::Inner::X1; namespace N2 { using namespace N1; - template struct X0; // expected-error{{not in a namespace enclosing}} + template struct X0; // expected-error{{must occur in namespace 'N1'}} template struct X2; // expected-error{{at global scope}} }