From a108760b336b9a2cab5d07a614987e87bb951d64 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 10 Mar 2014 00:04:29 +0000 Subject: [PATCH] When a type's definition is instantiated, the definition becomes visible, even if the type's declaration was previously instantiated in an unimported module. (For an imported type definition, this already worked, because the source location is set to the location of the definition, but for locally-instantiated type definitions, it did not.) llvm-svn: 203425 --- clang/lib/Sema/SemaTemplateInstantiate.cpp | 15 ++++++- .../template-specialization-visibility/a.h | 8 ++++ .../template-specialization-visibility/b.h | 7 +++ .../template-specialization-visibility/c.h | 6 +++ .../template-specialization-visibility/d.h | 5 +++ .../template-specialization-visibility/e.h | 6 +++ .../module.map | 7 +++ .../template-specialization-visibility.cpp | 43 +++++++++++++++++++ 8 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 clang/test/Modules/Inputs/template-specialization-visibility/a.h create mode 100644 clang/test/Modules/Inputs/template-specialization-visibility/b.h create mode 100644 clang/test/Modules/Inputs/template-specialization-visibility/c.h create mode 100644 clang/test/Modules/Inputs/template-specialization-visibility/d.h create mode 100644 clang/test/Modules/Inputs/template-specialization-visibility/e.h create mode 100644 clang/test/Modules/Inputs/template-specialization-visibility/module.map create mode 100644 clang/test/Modules/template-specialization-visibility.cpp 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