diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index bef073080bfa..7faaecefa88d 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2018,7 +2018,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Spec->setTemplateSpecializationKind(TSK); Spec->setPointOfInstantiation(PointOfInstantiation); } - + InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst.isInvalid()) return true; @@ -2040,7 +2040,12 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Start the definition of this instantiation. Instantiation->startDefinition(); - + + // The instantiation is visible here, even if it was first declared in an + // unimported module. + Instantiation->setHidden(false); + + // FIXME: This loses the as-written tag kind for an explicit instantiation. Instantiation->setTagKind(Pattern->getTagKind()); // Do substitution on the base class specifiers. @@ -2167,6 +2172,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, ActOnFinishDelayedMemberInitializers(Instantiation); + // FIXME: We should do something similar for explicit instantiations so they + // end up in the right module. if (TSK == TSK_ImplicitInstantiation) { Instantiation->setLocation(Pattern->getLocation()); Instantiation->setLocStart(Pattern->getInnerLocStart()); @@ -2256,6 +2263,10 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation, if (Inst.isInvalid()) return true; + // The instantiation is visible here, even if it was first declared in an + // unimported module. + Instantiation->setHidden(false); + // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. ContextRAII SavedContext(*this, Instantiation); diff --git a/clang/test/Modules/Inputs/template-specialization-visibility/a.h b/clang/test/Modules/Inputs/template-specialization-visibility/a.h new file mode 100644 index 000000000000..e88205558726 --- /dev/null +++ b/clang/test/Modules/Inputs/template-specialization-visibility/a.h @@ -0,0 +1,8 @@ +#ifndef A_H +#define A_H +template struct S; +template struct T { + struct S; + enum E : int; +}; +#endif diff --git a/clang/test/Modules/Inputs/template-specialization-visibility/b.h b/clang/test/Modules/Inputs/template-specialization-visibility/b.h new file mode 100644 index 000000000000..1a098262456a --- /dev/null +++ b/clang/test/Modules/Inputs/template-specialization-visibility/b.h @@ -0,0 +1,7 @@ +#ifndef B_H +#define B_H +#include "a.h" +S *s1; +T::S *s2; +T::E e1; +#endif diff --git a/clang/test/Modules/Inputs/template-specialization-visibility/c.h b/clang/test/Modules/Inputs/template-specialization-visibility/c.h new file mode 100644 index 000000000000..a92fb3b4c60c --- /dev/null +++ b/clang/test/Modules/Inputs/template-specialization-visibility/c.h @@ -0,0 +1,6 @@ +#ifndef C_H +#define C_H +template struct S { int n; }; +template struct T::S { int n; }; +template enum T::E : int { e }; +#endif diff --git a/clang/test/Modules/Inputs/template-specialization-visibility/d.h b/clang/test/Modules/Inputs/template-specialization-visibility/d.h new file mode 100644 index 000000000000..3048272c5f2d --- /dev/null +++ b/clang/test/Modules/Inputs/template-specialization-visibility/d.h @@ -0,0 +1,5 @@ +#ifndef D_H +#define D_H +template struct S; +template struct T; +#endif diff --git a/clang/test/Modules/Inputs/template-specialization-visibility/e.h b/clang/test/Modules/Inputs/template-specialization-visibility/e.h new file mode 100644 index 000000000000..5d6b14290471 --- /dev/null +++ b/clang/test/Modules/Inputs/template-specialization-visibility/e.h @@ -0,0 +1,6 @@ +#ifndef E_H +#define E_H +#include "c.h" +template struct S; +template struct T; +#endif diff --git a/clang/test/Modules/Inputs/template-specialization-visibility/module.map b/clang/test/Modules/Inputs/template-specialization-visibility/module.map new file mode 100644 index 000000000000..f0e2a0ef9022 --- /dev/null +++ b/clang/test/Modules/Inputs/template-specialization-visibility/module.map @@ -0,0 +1,7 @@ +module tsv { + module a { header "a.h" } + module b { header "b.h" } + module c { header "c.h" } + module d { header "d.h" } + module e { header "e.h" } +} diff --git a/clang/test/Modules/template-specialization-visibility.cpp b/clang/test/Modules/template-specialization-visibility.cpp new file mode 100644 index 000000000000..cc11a173e1dd --- /dev/null +++ b/clang/test/Modules/template-specialization-visibility.cpp @@ -0,0 +1,43 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -verify -fmodules-cache-path=%t -I %S/Inputs/template-specialization-visibility -std=c++11 %s +// +// FIXME: We should accept the explicit instantiation cases below too. +// Note, errors trigger implicit imports, so only enable one error at a time. +// RUN: %clang_cc1 -fmodules -verify -fmodules-cache-path=%t -I %S/Inputs/template-specialization-visibility -std=c++11 -DERR1 %s +// RUN: %clang_cc1 -fmodules -verify -fmodules-cache-path=%t -I %S/Inputs/template-specialization-visibility -std=c++11 -DERR2 %s +// RUN: %clang_cc1 -fmodules -verify -fmodules-cache-path=%t -I %S/Inputs/template-specialization-visibility -std=c++11 -DERR3 %s + +#include "c.h" + +S implicit_inst_class_template; +int k1 = implicit_inst_class_template.n; + +#ifdef ERR1 +S explicit_inst_class_template; // expected-error {{must be imported from module 'tsv.e'}} +// expected-note@e.h:4 {{previous}} +int k2 = explicit_inst_class_template.n; +#endif + +#include "a.h" + +T::S implicit_inst_member_class_template; +int k3 = implicit_inst_member_class_template.n; + +#ifdef ERR2 +T::S explicit_inst_member_class_template; // expected-error {{must be imported from module 'tsv.e'}} +// expected-note@e.h:5 {{previous}} +int k4 = explicit_inst_member_class_template.n; +#endif + +T::E implicit_inst_member_enum_template; +int k5 = decltype(implicit_inst_member_enum_template)::e; + +#ifdef ERR3 +T::E explicit_inst_member_enum_template; // expected-error {{must be imported from module 'tsv.e'}} +// expected-note@e.h:5 {{previous}} +int k6 = decltype(explicit_inst_member_enum_template)::e; +#endif + +#if ERR1 + ERR2 + ERR3 == 0 +// expected-no-diagnostics +#endif