[cfe-commits] r84154 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaTemplate.cpp test/CXX/temp/temp.spec/temp.explicit/p2.cpp test/SemaTemplate/explicit-instantiation.cpp test/SemaTemplate/temp_explicit.cpp
Douglas Gregor
dgregor at apple.com
Wed Oct 14 16:41:35 PDT 2009
Author: dgregor
Date: Wed Oct 14 18:41:34 2009
New Revision: 84154
URL: http://llvm.org/viewvc/llvm-project?rev=84154&view=rev
Log:
Additional semantic checking for explicit template instantiations,
focusing on the scope- and qualifier-related semantic requirements in
C++ [temp.explicit]p2.
Added:
cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p2.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp
cfe/trunk/test/SemaTemplate/temp_explicit.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=84154&r1=84153&r2=84154&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Oct 14 18:41:34 2009
@@ -1085,6 +1085,9 @@
"non-templated declaration is here">;
def err_explicit_instantiation_out_of_scope : Error<
"explicit instantiation of %0 not in a namespace enclosing %1">;
+def err_explicit_instantiation_must_be_global : Error<
+ "explicit instantiation of %0 must occur at global scope">;
+
def err_explicit_instantiation_requires_name : Error<
"explicit instantiation declaration requires a name">;
def err_explicit_instantiation_of_typedef : Error<
@@ -1106,6 +1109,12 @@
"explicit instantiation candidate function template here %0">;
def err_explicit_instantiation_inline : Error<
"explicit instantiation cannot be 'inline'">;
+def err_explicit_instantiation_without_qualified_id : Error<
+ "qualifier in explicit instantiation of %q0 requires a template-id">;
+def err_explicit_instantiation_without_qualified_id_quals : Error<
+ "qualifier in explicit instantiation of '%0%1' requires a template-id">;
+def err_explicit_instantiation_unqualified_wrong_namespace : Error<
+ "explicit instantiation of %q0 must occur in %1">;
// C++ typename-specifiers
def err_typename_nested_not_found : Error<"no type named %0 in %1">;
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=84154&r1=84153&r2=84154&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Oct 14 18:41:34 2009
@@ -2421,7 +2421,7 @@
/// \param IsPartialSpecialization whether this is a partial specialization of
/// a class template.
///
-/// \param TSK the kind of specialization or implicit instantiation being
+/// \param TSK the kind of specialization or explicit instantiation being
/// performed.
///
/// \returns true if there was an error that we cannot recover from, false
@@ -3325,6 +3325,68 @@
return false;
}
+/// \brief Check the scope of an explicit instantiation.
+static void CheckExplicitInstantiationScope(Sema &S, NamedDecl *D,
+ SourceLocation InstLoc,
+ bool WasQualifiedName) {
+ DeclContext *ExpectedContext
+ = D->getDeclContext()->getEnclosingNamespaceContext()->getLookupContext();
+ DeclContext *CurContext = S.CurContext->getLookupContext();
+
+ // C++0x [temp.explicit]p2:
+ // An explicit instantiation shall appear in an enclosing namespace of its
+ // template.
+ //
+ // This is DR275, which we do not retroactively apply to C++98/03.
+ if (S.getLangOptions().CPlusPlus0x &&
+ !CurContext->Encloses(ExpectedContext)) {
+ if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ExpectedContext))
+ S.Diag(InstLoc, diag::err_explicit_instantiation_out_of_scope)
+ << D << NS;
+ else
+ S.Diag(InstLoc, diag::err_explicit_instantiation_must_be_global)
+ << D;
+ S.Diag(D->getLocation(), diag::note_explicit_instantiation_here);
+ return;
+ }
+
+ // 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;
+
+ if (CurContext->Equals(ExpectedContext))
+ return;
+
+ S.Diag(InstLoc, diag::err_explicit_instantiation_unqualified_wrong_namespace)
+ << D << ExpectedContext;
+ S.Diag(D->getLocation(), diag::note_explicit_instantiation_here);
+}
+
+/// \brief Determine whether the given scope specifier has a template-id in it.
+static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) {
+ if (!SS.isSet())
+ return false;
+
+ // C++0x [temp.explicit]p2:
+ // 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
+ // name shall be a simple-template-id.
+ //
+ // C++98 has the same restriction, just worded differently.
+ for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
+ NNS; NNS = NNS->getPrefix())
+ if (Type *T = NNS->getAsType())
+ if (isa<TemplateSpecializationType>(T))
+ return true;
+
+ return false;
+}
+
// Explicit instantiation of a class template specialization
// FIXME: Implement extern template semantics
Sema::DeclResult
@@ -3367,6 +3429,10 @@
Kind = ClassTemplate->getTemplatedDecl()->getTagKind();
}
+ // C++0x [temp.explicit]p2:
+ // There are two forms of explicit instantiation: an explicit instantiation
+ // definition and an explicit instantiation declaration. An explicit
+ // instantiation declaration begins with the extern keyword. [...]
TemplateSpecializationKind TSK
= ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
: TSK_ExplicitInstantiationDeclaration;
@@ -3404,10 +3470,8 @@
// namespace of its template. [...]
//
// This is C++ DR 275.
- if (CheckTemplateSpecializationScope(*this, ClassTemplate, PrevDecl,
- TemplateNameLoc, false,
- TSK))
- return true;
+ CheckExplicitInstantiationScope(*this, ClassTemplate, TemplateNameLoc,
+ SS.isSet());
ClassTemplateSpecializationDecl *Specialization = 0;
@@ -3563,7 +3627,7 @@
if (Tag->isInvalidDecl())
return true;
-
+
CXXRecordDecl *Record = cast<CXXRecordDecl>(Tag);
CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass();
if (!Pattern) {
@@ -3573,7 +3637,20 @@
return true;
}
- // What kind of explicit instantiation? (for C++0x, GNU extern templates).
+ // C++0x [temp.explicit]p2:
+ // If the explicit instantiation is for a class or member class, the
+ // elaborated-type-specifier in the declaration shall include a
+ // simple-template-id.
+ //
+ // C++98 has the same restriction, just worded differently.
+ if (!ScopeSpecifierHasTemplateId(SS))
+ Diag(TemplateLoc, diag::err_explicit_instantiation_without_qualified_id)
+ << Record << SS.getRange();
+
+ // C++0x [temp.explicit]p2:
+ // There are two forms of explicit instantiation: an explicit instantiation
+ // definition and an explicit instantiation declaration. An explicit
+ // instantiation declaration begins with the extern keyword. [...]
TemplateSpecializationKind TSK
= ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
: TSK_ExplicitInstantiationDeclaration;
@@ -3583,11 +3660,7 @@
// namespace of its template. [...]
//
// This is C++ DR 275.
- if (CheckTemplateSpecializationScope(*this, Record,
- Record->getPreviousDeclaration(),
- NameLoc, false,
- TSK))
- return true;
+ CheckExplicitInstantiationScope(*this, Record, NameLoc, true);
if (!Record->getDefinition(Context)) {
// If the class has a definition, instantiate it (and all of its
@@ -3655,11 +3728,14 @@
// FIXME: check for constexpr specifier.
- // Determine what kind of explicit instantiation we have.
+ // C++0x [temp.explicit]p2:
+ // There are two forms of explicit instantiation: an explicit instantiation
+ // definition and an explicit instantiation declaration. An explicit
+ // instantiation declaration begins with the extern keyword. [...]
TemplateSpecializationKind TSK
= ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
: TSK_ExplicitInstantiationDeclaration;
-
+
LookupResult Previous;
LookupParsedName(Previous, S, &D.getCXXScopeSpec(),
Name, LookupOrdinaryName);
@@ -3696,6 +3772,21 @@
return true;
}
+ // C++0x [temp.explicit]p2:
+ // 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
+ // name shall be a simple-template-id.
+ //
+ // C++98 has the same restriction, just worded differently.
+ if (!ScopeSpecifierHasTemplateId(D.getCXXScopeSpec()))
+ Diag(D.getIdentifierLoc(),
+ diag::err_explicit_instantiation_without_qualified_id)
+ << Prev << D.getCXXScopeSpec().getRange();
+
+ // Check the scope of this explicit instantiation.
+ CheckExplicitInstantiationScope(*this, Prev, D.getIdentifierLoc(), true);
+
// Instantiate static data member.
// FIXME: Check for prior specializations and such.
Prev->setTemplateSpecializationKind(TSK);
@@ -3806,6 +3897,29 @@
break;
}
+ // Check the scope of this explicit instantiation.
+ FunctionTemplateDecl *FunTmpl = Specialization->getPrimaryTemplate();
+
+ // C++0x [temp.explicit]p2:
+ // 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
+ // name shall be a simple-template-id.
+ //
+ // C++98 has the same restriction, just worded differently.
+ if (D.getKind() != Declarator::DK_TemplateId && !FunTmpl &&
+ D.getCXXScopeSpec().isSet() &&
+ !ScopeSpecifierHasTemplateId(D.getCXXScopeSpec()))
+ Diag(D.getIdentifierLoc(),
+ diag::err_explicit_instantiation_without_qualified_id)
+ << Specialization << D.getCXXScopeSpec().getRange();
+
+ CheckExplicitInstantiationScope(*this,
+ FunTmpl? (NamedDecl *)FunTmpl
+ : Specialization->getInstantiatedFromMemberFunction(),
+ D.getIdentifierLoc(),
+ D.getCXXScopeSpec().isSet());
+
// FIXME: Create some kind of ExplicitInstantiationDecl here.
return DeclPtrTy();
}
Added: cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p2.cpp?rev=84154&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p2.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p2.cpp Wed Oct 14 18:41:34 2009
@@ -0,0 +1,43 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Example from the standard
+template<class T> class Array { void mf() { } };
+
+template class Array<char>;
+template void Array<int>::mf();
+template<class T> void sort(Array<T>& v) { /* ... */ }
+template void sort(Array<char>&);
+namespace N {
+ template<class T> void f(T&) { }
+}
+template void N::f<int>(int&);
+
+
+template<typename T>
+struct X0 {
+ struct Inner {};
+ void f() { }
+ static T value;
+};
+
+template<typename T>
+T X0<T>::value = 17;
+
+typedef X0<int> XInt;
+
+template struct XInt::Inner; // expected-error{{template-id}}
+template void XInt::f(); // expected-error{{template-id}}
+template int XInt::value; // expected-error{{template-id}}
+
+namespace N {
+ template<typename T>
+ struct X1 { // expected-note{{explicit instantiation refers here}}
+ };
+
+ template<typename T>
+ void f1(T); // expected-note{{explicit instantiation refers here}}
+}
+using namespace N;
+
+template struct X1<int>; // expected-error{{must occur in}}
+template void f1(int); // expected-error{{must occur in}}
Modified: cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp?rev=84154&r1=84153&r2=84154&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp (original)
+++ cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp Wed Oct 14 18:41:34 2009
@@ -14,19 +14,22 @@
T f0(T x) {
return x + 1; // expected-error{{invalid operands}}
}
- T* f0(T*, T*);
+ T* f0(T*, T*) { return T(); }
template<typename U>
- T f0(T, U);
+ T f0(T, U) { return T(); }
};
+template<typename T>
+T X0<T>::value; // expected-error{{no matching constructor}}
+
template int X0<int>::value;
struct NotDefaultConstructible {
NotDefaultConstructible(int);
};
-template NotDefaultConstructible X0<NotDefaultConstructible>::value;
+template NotDefaultConstructible X0<NotDefaultConstructible>::value; // expected-note{{instantiation}}
template int X0<int>::f0(int);
template int* X0<int>::f0(int*, int*);
@@ -43,11 +46,11 @@
struct X2 {
int f0(int); // expected-note{{refers here}}
- template<typename T> T f1(T);
- template<typename T> T* f1(T*);
+ template<typename T> T f1(T) { return T(); }
+ template<typename T> T* f1(T*) { return 0; }
- template<typename T, typename U> void f2(T, U*); // expected-note{{candidate}}
- template<typename T, typename U> void f2(T*, U); // expected-note{{candidate}}
+ template<typename T, typename U> void f2(T, U*) { } // expected-note{{candidate}}
+ template<typename T, typename U> void f2(T*, U) { } // expected-note{{candidate}}
};
template int X2::f0(int); // expected-error{{not an instantiation}}
@@ -57,12 +60,12 @@
template void X2::f2(int *, int *); // expected-error{{ambiguous}}
-template<typename T> void print_type();
+template<typename T> void print_type() { }
template void print_type<int>();
template void print_type<float>();
-template<typename T> void print_type(T*);
+template<typename T> void print_type(T*) { }
template void print_type(int*);
template void print_type<int>(float*); // expected-error{{does not refer}}
Modified: cfe/trunk/test/SemaTemplate/temp_explicit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_explicit.cpp?rev=84154&r1=84153&r2=84154&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_explicit.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_explicit.cpp Wed Oct 14 18:41:34 2009
@@ -15,7 +15,6 @@
template class ::N::X1<int, float>;
using namespace N;
-template class X1<float>;
// Check for some bogus syntax that probably means that the user
// wanted to write an explicit specialization, but forgot the '<>'
More information about the cfe-commits
mailing list