Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -466,10 +466,14 @@ const NamedDecl *PatternDef, TemplateSpecializationKind TSK, bool Complain /*= true*/) { - assert(isa(Instantiation) || isa(Instantiation)); + assert(isa(Instantiation) || isa(Instantiation) || + isa(Instantiation)); - if (PatternDef && (isa(PatternDef) - || !cast(PatternDef)->isBeingDefined())) { + bool IsEntityBeingDefined = false; + if (const TagDecl *TD = dyn_cast_or_null(PatternDef)) + IsEntityBeingDefined = TD->isBeingDefined(); + + if (PatternDef && !IsEntityBeingDefined) { NamedDecl *SuggestedDef = nullptr; if (!hasVisibleDefinition(const_cast(PatternDef), &SuggestedDef, /*OnlyNeedComplete*/false)) { @@ -486,6 +490,7 @@ if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) return true; + llvm::Optional Note; QualType InstantiationTy; if (TagDecl *TD = dyn_cast(Instantiation)) InstantiationTy = Context.getTypeDeclType(TD); @@ -502,27 +507,40 @@ Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_member) << 1 << Instantiation->getDeclName() << Instantiation->getDeclContext(); - } else { + Note = diag::note_explicit_instantiation_here; + } else if (isa(Instantiation)) { Diag(PointOfInstantiation, diag::err_implicit_instantiate_member_undefined) << InstantiationTy; + Note = diag::note_member_declared_at; } - Diag(Pattern->getLocation(), isa(Instantiation) - ? diag::note_explicit_instantiation_here - : diag::note_member_declared_at); } else { - if (isa(Instantiation)) + if (isa(Instantiation)) { Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_func_template) << Pattern; - else + Note = diag::note_explicit_instantiation_here; + } else if (isa(Instantiation)) { Diag(PointOfInstantiation, diag::err_template_instantiate_undefined) << (TSK != TSK_ImplicitInstantiation) << InstantiationTy; - Diag(Pattern->getLocation(), isa(Instantiation) - ? diag::note_explicit_instantiation_here - : diag::note_template_decl_here); + Note = diag::note_template_decl_here; + } else if (isa(Instantiation)) { + if (isa(Instantiation)) { + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_var_template) + << Instantiation; + Instantiation->setInvalidDecl(); + } else + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_member) + << 2 << Instantiation->getDeclName() + << Instantiation->getDeclContext(); + Note = diag::note_explicit_instantiation_here; + } } + if (Note) // Diagnostics were emitted. + Diag(Pattern->getLocation(), Note.getValue()); // In general, Instantiation isn't marked invalid to get more than one // error for multiple undefined instantiations. But the code that does Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4067,6 +4067,10 @@ PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(), "instantiating variable initializer"); + // The instantiation is visible here, even if it was first declared in an + // unimported module. + Var->setHidden(false); + // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate // later, while we're still within our own instantiation context. @@ -4115,33 +4119,17 @@ Def = PatternDecl->getDefinition(); } - // FIXME: Check that the definition is visible before trying to instantiate - // it. This requires us to track the instantiation stack in order to know - // which definitions should be visible. + TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind(); // If we don't have a definition of the variable template, we won't perform // any instantiation. Rather, we rely on the user to instantiate this // definition (or provide a specialization for it) in another translation // unit. - if (!Def) { - if (DefinitionRequired) { - if (VarSpec) - Diag(PointOfInstantiation, - diag::err_explicit_instantiation_undefined_var_template) << Var; - else - Diag(PointOfInstantiation, - diag::err_explicit_instantiation_undefined_member) - << 2 << Var->getDeclName() << Var->getDeclContext(); - Diag(PatternDecl->getLocation(), - diag::note_explicit_instantiation_here); - if (VarSpec) - Var->setInvalidDecl(); - } else if (Var->getTemplateSpecializationKind() - == TSK_ExplicitInstantiationDefinition) { + if (!Def && !DefinitionRequired) { + if (TSK == TSK_ExplicitInstantiationDefinition) { PendingInstantiations.push_back( std::make_pair(Var, PointOfInstantiation)); - } else if (Var->getTemplateSpecializationKind() - == TSK_ImplicitInstantiation) { + } else if (TSK == TSK_ImplicitInstantiation) { // Warn about missing definition at the end of translation unit. if (AtEndOfTU && !getDiagnostics().hasErrorOccurred()) { Diag(PointOfInstantiation, diag::warn_var_template_missing) @@ -4150,12 +4138,19 @@ if (getLangOpts().CPlusPlus11) Diag(PointOfInstantiation, diag::note_inst_declaration_hint) << Var; } + return; } - return; } - TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind(); + // FIXME: We need to track the instantiation stack in order to know which + // definitions should be visible within this instantiation. + if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Var, + /*InstantiatedFromMember*/false, + PatternDecl, Def, TSK, + /*Complain*/DefinitionRequired)) + return; + // Never instantiate an explicit specialization. if (TSK == TSK_ExplicitSpecialization) Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -6894,6 +6894,12 @@ if (auto *Pattern = FD->getTemplateInstantiationPattern()) FD = Pattern; D = FD->getDefinition(); + } else if (auto *VD = dyn_cast(D)) { + // FIXME: Handle the case where D is a VarTemplateSpecializationDecl, i.e. D + // is not a static data member. + if (auto *Pattern = VD->getInstantiatedFromStaticDataMember()) + VD = Pattern; + D = VD->getDefinition(); } assert(D && "missing definition for pattern of instantiated definition"); Index: test/Modules/Inputs/PR28752/Subdir1/b.h =================================================================== --- /dev/null +++ test/Modules/Inputs/PR28752/Subdir1/b.h @@ -0,0 +1 @@ +#include Index: test/Modules/Inputs/PR28752/Subdir1/module.modulemap =================================================================== --- /dev/null +++ test/Modules/Inputs/PR28752/Subdir1/module.modulemap @@ -0,0 +1,5 @@ +module b { + module "b.h" { header "b.h" export * } + module "c.h" { header "c.h" export * } + export * +} Index: test/Modules/Inputs/PR28752/a.h =================================================================== --- /dev/null +++ test/Modules/Inputs/PR28752/a.h @@ -0,0 +1 @@ +#include Index: test/Modules/Inputs/PR28752/module.modulemap =================================================================== --- /dev/null +++ test/Modules/Inputs/PR28752/module.modulemap @@ -0,0 +1 @@ +module a { header "a.h" export * } Index: test/Modules/Inputs/PR28752/vector =================================================================== --- /dev/null +++ test/Modules/Inputs/PR28752/vector @@ -0,0 +1,28 @@ +#ifndef VECTOR +#define VECTOR +template struct B; +template struct B { typedef _Tp type; }; +namespace std { +template struct D { + + template struct F { + static const bool value = 0; + }; + + template + typename B::value, _Alloc2>::type _S_select(_Alloc2); + template + static + typename B::value, _Alloc2>::type _S_select(_Alloc2); +}; +template +template +const bool D<_Alloc>::F<_Alloc2>::value; + +template class vector { +public: + vector(int); + vector(vector &) : vector(D::_S_select((bool)0)) {} +}; +} +#endif // VECTOR \ No newline at end of file Index: test/Modules/pr28752.cpp =================================================================== --- /dev/null +++ test/Modules/pr28752.cpp @@ -0,0 +1,19 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -std=c++11 -nostdsysteminc -I%S/Inputs/PR28752 -verify %s +// RUN: %clang_cc1 -std=c++11 -nostdsysteminc -fmodules -fmodule-map-file=%S/Inputs/PR28752/Subdir1/module.modulemap -fmodule-map-file=%S/Inputs/PR28752/module.modulemap -fmodules-cache-path=%t -I%S/Inputs/PR28752 -I%S/Inputs/PR28752/Subdir1 -verify %s + +#include "a.h" +#include "Subdir1/c.h" +#include + +class TClingClassInfo { + std::vector fIterStack; +}; + +TClingClassInfo *a; +class TClingBaseClassInfo { + TClingBaseClassInfo() { new TClingClassInfo(*a); } +}; + +// expected-no-diagnostics +