зеркало из https://github.com/microsoft/clang-1.git
Check the interactions between explicit instantiations and template
specializations. Work in progress; there's more cleanup required to actually use the new CheckSpecializationInstantiationRedecl checker uniformly. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84185 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
f65b9f58f4
Коммит
454885ec4f
|
@ -1117,6 +1117,11 @@ def err_explicit_instantiation_undefined_member : Error<
|
|||
"static data member}0 %1 of class template %2">;
|
||||
def err_explicit_instantiation_undefined_func_template : Error<
|
||||
"explicit instantiation of undefined function template %0">;
|
||||
def err_explicit_instantiation_declaration_after_definition : Error<
|
||||
"explicit instantiation declaration (with 'extern') follows explicit "
|
||||
"instantiation definition (without 'extern')">;
|
||||
def note_explicit_instantiation_definition_here : Note<
|
||||
"explicit instantiation definition is here">;
|
||||
|
||||
// C++ typename-specifiers
|
||||
def err_typename_nested_not_found : Error<"no type named %0 in %1">;
|
||||
|
|
|
@ -3038,6 +3038,173 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
|
|||
return DeclPtrTy();
|
||||
}
|
||||
|
||||
/// \brief Diagnose cases where we have an explicit template specialization
|
||||
/// before/after an explicit template instantiation, producing diagnostics
|
||||
/// for those cases where they are required and determining whether the
|
||||
/// new specialization/instantiation will have any effect.
|
||||
///
|
||||
/// \param S the semantic analysis object.
|
||||
///
|
||||
/// \param NewLoc the location of the new explicit specialization or
|
||||
/// instantiation.
|
||||
///
|
||||
/// \param NewTSK the kind of the new explicit specialization or instantiation.
|
||||
///
|
||||
/// \param PrevDecl the previous declaration of the entity.
|
||||
///
|
||||
/// \param PrevTSK the kind of the old explicit specialization or instantiatin.
|
||||
///
|
||||
/// \param PrevPointOfInstantiation if valid, indicates where the previus
|
||||
/// declaration was instantiated (either implicitly or explicitly).
|
||||
///
|
||||
/// \param SuppressNew will be set to true to indicate that the new
|
||||
/// specialization or instantiation has no effect and should be ignored.
|
||||
///
|
||||
/// \returns true if there was an error that should prevent the introduction of
|
||||
/// the new declaration into the AST, false otherwise.
|
||||
static bool
|
||||
CheckSpecializationInstantiationRedecl(Sema &S,
|
||||
SourceLocation NewLoc,
|
||||
TemplateSpecializationKind NewTSK,
|
||||
NamedDecl *PrevDecl,
|
||||
TemplateSpecializationKind PrevTSK,
|
||||
SourceLocation PrevPointOfInstantiation,
|
||||
bool &SuppressNew) {
|
||||
SuppressNew = false;
|
||||
|
||||
switch (NewTSK) {
|
||||
case TSK_Undeclared:
|
||||
case TSK_ImplicitInstantiation:
|
||||
assert(false && "Don't check implicit instantiations here");
|
||||
return false;
|
||||
|
||||
case TSK_ExplicitSpecialization:
|
||||
switch (PrevTSK) {
|
||||
case TSK_Undeclared:
|
||||
case TSK_ExplicitSpecialization:
|
||||
// Okay, we're just specializing something that is either already
|
||||
// explicitly specialized or has merely been mentioned without any
|
||||
// instantiation.
|
||||
return false;
|
||||
|
||||
case TSK_ImplicitInstantiation:
|
||||
if (PrevPointOfInstantiation.isInvalid()) {
|
||||
// The declaration itself has not actually been instantiated, so it is
|
||||
// still okay to specialize it.
|
||||
return false;
|
||||
}
|
||||
// Fall through
|
||||
|
||||
case TSK_ExplicitInstantiationDeclaration:
|
||||
case TSK_ExplicitInstantiationDefinition:
|
||||
assert((PrevTSK == TSK_ImplicitInstantiation ||
|
||||
PrevPointOfInstantiation.isValid()) &&
|
||||
"Explicit instantiation without point of instantiation?");
|
||||
|
||||
// C++ [temp.expl.spec]p6:
|
||||
// If a template, a member template or the member of a class template
|
||||
// is explicitly specialized then that specialization shall be declared
|
||||
// before the first use of that specialization that would cause an
|
||||
// implicit instantiation to take place, in every translation unit in
|
||||
// which such a use occurs; no diagnostic is required.
|
||||
S.Diag(NewLoc, diag::err_specialization_after_instantiation)
|
||||
<< PrevDecl;
|
||||
S.Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here)
|
||||
<< (PrevTSK != TSK_ImplicitInstantiation);
|
||||
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case TSK_ExplicitInstantiationDeclaration:
|
||||
switch (PrevTSK) {
|
||||
case TSK_ExplicitInstantiationDeclaration:
|
||||
// This explicit instantiation declaration is redundant (that's okay).
|
||||
SuppressNew = true;
|
||||
return false;
|
||||
|
||||
case TSK_Undeclared:
|
||||
case TSK_ImplicitInstantiation:
|
||||
// We're explicitly instantiating something that may have already been
|
||||
// implicitly instantiated; that's fine.
|
||||
return false;
|
||||
|
||||
case TSK_ExplicitSpecialization:
|
||||
// C++0x [temp.explicit]p4:
|
||||
// For a given set of template parameters, if an explicit instantiation
|
||||
// of a template appears after a declaration of an explicit
|
||||
// specialization for that template, the explicit instantiation has no
|
||||
// effect.
|
||||
return false;
|
||||
|
||||
case TSK_ExplicitInstantiationDefinition:
|
||||
// C++0x [temp.explicit]p10:
|
||||
// If an entity is the subject of both an explicit instantiation
|
||||
// declaration and an explicit instantiation definition in the same
|
||||
// translation unit, the definition shall follow the declaration.
|
||||
S.Diag(NewLoc,
|
||||
diag::err_explicit_instantiation_declaration_after_definition);
|
||||
S.Diag(PrevPointOfInstantiation,
|
||||
diag::note_explicit_instantiation_definition_here);
|
||||
assert(PrevPointOfInstantiation.isValid() &&
|
||||
"Explicit instantiation without point of instantiation?");
|
||||
SuppressNew = true;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case TSK_ExplicitInstantiationDefinition:
|
||||
switch (PrevTSK) {
|
||||
case TSK_Undeclared:
|
||||
case TSK_ImplicitInstantiation:
|
||||
// We're explicitly instantiating something that may have already been
|
||||
// implicitly instantiated; that's fine.
|
||||
return false;
|
||||
|
||||
case TSK_ExplicitSpecialization:
|
||||
// C++ DR 259, C++0x [temp.explicit]p4:
|
||||
// For a given set of template parameters, if an explicit
|
||||
// instantiation of a template appears after a declaration of
|
||||
// an explicit specialization for that template, the explicit
|
||||
// instantiation has no effect.
|
||||
//
|
||||
// In C++98/03 mode, we only give an extension warning here, because it
|
||||
// is not not harmful to try to explicitly instantiate something that
|
||||
// has been explicitly specialized.
|
||||
if (!S.getLangOptions().CPlusPlus0x) {
|
||||
S.Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization)
|
||||
<< PrevDecl;
|
||||
S.Diag(PrevDecl->getLocation(),
|
||||
diag::note_previous_template_specialization);
|
||||
}
|
||||
SuppressNew = true;
|
||||
return false;
|
||||
|
||||
case TSK_ExplicitInstantiationDeclaration:
|
||||
// We're explicity instantiating a definition for something for which we
|
||||
// were previously asked to suppress instantiations. That's fine.
|
||||
return false;
|
||||
|
||||
case TSK_ExplicitInstantiationDefinition:
|
||||
// C++0x [temp.spec]p5:
|
||||
// For a given template and a given set of template-arguments,
|
||||
// - an explicit instantiation definition shall appear at most once
|
||||
// in a program,
|
||||
S.Diag(NewLoc, diag::err_explicit_instantiation_duplicate)
|
||||
<< PrevDecl;
|
||||
S.Diag(PrevPointOfInstantiation,
|
||||
diag::note_previous_explicit_instantiation);
|
||||
SuppressNew = true;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
assert(false && "Missing specialization/instantiation case?");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Perform semantic analysis for the given function template
|
||||
/// specialization.
|
||||
///
|
||||
|
@ -3649,7 +3816,23 @@ Sema::ActOnExplicitInstantiation(Scope *S,
|
|||
//
|
||||
// This is C++ DR 275.
|
||||
CheckExplicitInstantiationScope(*this, Record, NameLoc, true);
|
||||
|
||||
|
||||
// Verify that it is okay to explicitly instantiate here.
|
||||
if (CXXRecordDecl *PrevDecl
|
||||
= cast_or_null<CXXRecordDecl>(Record->getPreviousDeclaration())) {
|
||||
MemberSpecializationInfo *MSInfo = PrevDecl->getMemberSpecializationInfo();
|
||||
bool SuppressNew = false;
|
||||
assert(MSInfo && "No member specialization information?");
|
||||
if (CheckSpecializationInstantiationRedecl(*this, TemplateLoc, TSK,
|
||||
PrevDecl,
|
||||
MSInfo->getTemplateSpecializationKind(),
|
||||
MSInfo->getPointOfInstantiation(),
|
||||
SuppressNew))
|
||||
return true;
|
||||
if (SuppressNew)
|
||||
return TagD;
|
||||
}
|
||||
|
||||
if (!Record->getDefinition(Context)) {
|
||||
// C++ [temp.explicit]p3:
|
||||
// A definition of a member class of a class template shall be in scope
|
||||
|
@ -3783,8 +3966,20 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
|
|||
// Check the scope of this explicit instantiation.
|
||||
CheckExplicitInstantiationScope(*this, Prev, D.getIdentifierLoc(), true);
|
||||
|
||||
// Verify that it is okay to explicitly instantiate here.
|
||||
MemberSpecializationInfo *MSInfo = Prev->getMemberSpecializationInfo();
|
||||
assert(MSInfo && "Missing static data member specialization info?");
|
||||
bool SuppressNew = false;
|
||||
if (CheckSpecializationInstantiationRedecl(*this, D.getIdentifierLoc(), TSK,
|
||||
Prev,
|
||||
MSInfo->getTemplateSpecializationKind(),
|
||||
MSInfo->getPointOfInstantiation(),
|
||||
SuppressNew))
|
||||
return true;
|
||||
if (SuppressNew)
|
||||
return DeclPtrTy();
|
||||
|
||||
// Instantiate static data member.
|
||||
// FIXME: Check for prior specializations and such.
|
||||
Prev->setTemplateSpecializationKind(TSK);
|
||||
if (TSK == TSK_ExplicitInstantiationDefinition)
|
||||
InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false,
|
||||
|
@ -3859,6 +4054,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
|
|||
if (!Specialization)
|
||||
return true;
|
||||
|
||||
// FIXME: Use CheckSpecializationInstantiationRedecl
|
||||
switch (Specialization->getTemplateSpecializationKind()) {
|
||||
case TSK_Undeclared:
|
||||
Diag(D.getIdentifierLoc(),
|
||||
|
|
|
@ -769,6 +769,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
|
|||
}
|
||||
Pattern = PatternDef;
|
||||
|
||||
// \brief Record the point of instantiation.
|
||||
if (MemberSpecializationInfo *MSInfo
|
||||
= Instantiation->getMemberSpecializationInfo()) {
|
||||
MSInfo->setTemplateSpecializationKind(TSK);
|
||||
MSInfo->setPointOfInstantiation(PointOfInstantiation);
|
||||
}
|
||||
|
||||
InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation);
|
||||
if (Inst)
|
||||
return true;
|
||||
|
|
|
@ -5,6 +5,8 @@ template void f0(int); // expected-error{{explicit instantiation of undefined fu
|
|||
|
||||
template<typename T>
|
||||
struct X0 {
|
||||
struct Inner;
|
||||
|
||||
void f1(); // expected-note{{here}}
|
||||
|
||||
static T value; // expected-note{{here}}
|
||||
|
@ -14,3 +16,17 @@ template void X0<int>::f1(); // expected-error{{explicit instantiation of undefi
|
|||
|
||||
template int X0<int>::value; // expected-error{{explicit instantiation of undefined static data member}}
|
||||
|
||||
template<> void f0(long);
|
||||
template void f0(long); // okay
|
||||
|
||||
template<> void X0<long>::f1();
|
||||
template void X0<long>::f1();
|
||||
|
||||
template<> struct X0<long>::Inner;
|
||||
template struct X0<long>::Inner;
|
||||
|
||||
template<> long X0<long>::value;
|
||||
template long X0<long>::value;
|
||||
|
||||
template<> struct X0<double>;
|
||||
template struct X0<double>;
|
||||
|
|
Загрузка…
Ссылка в новой задаче