On 11/27/24 3:53 AM, Nathaniel Shead wrote:
Gentle ping for this series:
https://gcc.gnu.org/pipermail/gcc-patches/2024-October/665108.html
Most of the patches no longer applied cleanly to trunk since the last
time I pinged this so I'm attaching newly rebased patches.
One slight adjustment I've included as well is a test in internal-4_b.C
for exposures of namespace aliases, as in:
namespace { namespace internal {} }
export namespace exposure = internal;
By the standard this appears to be well-formed; we currently error, and
I think this might be the desired behaviour (an easy workaround is to
wrap the alias in an anonymous namespace), but thought I'd at least test
the existing behaviour here.
Tested modules.exp on x86_64-pc-linux-gnu, OK for trunk if full
bootstrap+regtest succeeds?
I tweaked some of these patches a bit; OK with these changes, or without
patch #2 if you'd rather not make that change.
From 287c5053b59631be749a802a3b88f83572ec578a Mon Sep 17 00:00:00 2001
From: Jason Merrill <ja...@redhat.com>
Date: Fri, 13 Dec 2024 19:10:03 -0500
Subject: [PATCH] c++: adjust "Ignore TU-local entities where necessary"
To: gcc-patches@gcc.gnu.org
That commit message, and a comment in the code, mention explicit
instantiations as a case we might want to suppress
-Wtemplate-names-tu-local, but they previously weren't on
DECL_TEMPLATE_INSTANTIATIONS. This patch adds all function template
instantiations to that list in modules so that we can check for it.
gcc/cp/ChangeLog:
* cp-tree.h (DECL_TEMPLATE_INSTANTIATIONS): Update comment.
* module.cc (template_has_explicit_inst): New.
(depset::hash::finalize_dependencies): Use it.
* pt.cc (register_specialization): Always register in a module.
gcc/testsuite/ChangeLog:
* g++.dg/modules/internal-5_a.C: Remove some warnings.
---
gcc/cp/cp-tree.h | 23 +++++++++---------
gcc/cp/module.cc | 26 ++++++++++++++++++---
gcc/cp/pt.cc | 3 +++
gcc/testsuite/g++.dg/modules/internal-5_a.C | 4 ++--
4 files changed, 40 insertions(+), 16 deletions(-)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 216fdfa7b8a..d793e2bc8de 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5158,18 +5158,19 @@ get_vec_init_expr (tree t)
tree is converted to C++ class hiearchy. */
#define DECL_TEMPLATE_RESULT(NODE) \
((struct tree_template_decl *)CONST_CAST_TREE(TEMPLATE_DECL_CHECK (NODE)))->result
-/* For a function template at namespace scope, DECL_TEMPLATE_INSTANTIATIONS
- lists all instantiations and specializations of the function so that
- tsubst_friend_function can reassign them to another template if we find
- that the namespace-scope template is really a partial instantiation of a
- friend template.
+/* For a forward-declared function template at namespace scope, or for any
+ function template in an exporting module, DECL_TEMPLATE_INSTANTIATIONS lists
+ all instantiations and specializations of the function so that
+ tsubst_friend_function can reassign them to another template if we find that
+ the namespace-scope template is really a partial instantiation of a friend
+ template.
- For a class template the DECL_TEMPLATE_INSTANTIATIONS lists holds
- all instantiations and specializations of the class type, including
- partial instantiations and partial specializations, so that if we
- explicitly specialize a partial instantiation we can walk the list
- in maybe_process_partial_specialization and reassign them or complain
- as appropriate.
+ For a class or variable template the DECL_TEMPLATE_INSTANTIATIONS lists
+ holds all instantiations and specializations, including partial
+ instantiations and partial specializations, so that if we explicitly
+ specialize a partial instantiation we can walk the list in
+ maybe_process_partial_specialization and reassign them or complain as
+ appropriate.
In both cases, the TREE_PURPOSE of each node contains the arguments
used; the TREE_VALUE contains the generated variable. The template
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 6c5350064df..629863e4007 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -14491,6 +14491,24 @@ binding_cmp (const void *a_, const void *b_)
return DECL_UID (a_ent) < DECL_UID (b_ent) ? -1 : +1;
}
+/* True iff TMPL has an explicit instantiation definition.
+
+ This is local to module.cc because register_specialization skips adding most
+ instantiations unless module_maybe_has_cmi_p. */
+
+static bool
+template_has_explicit_inst (tree tmpl)
+{
+ for (tree t = DECL_TEMPLATE_INSTANTIATIONS (tmpl); t; t = TREE_CHAIN (t))
+ {
+ tree spec = TREE_VALUE (t);
+ if (DECL_EXPLICIT_INSTANTIATION (spec)
+ && !DECL_REALLY_EXTERN (spec))
+ return true;
+ }
+ return false;
+}
+
/* Sort the bindings, issue errors about bad internal refs. */
bool
@@ -14562,9 +14580,11 @@ depset::hash::finalize_dependencies ()
(TREE_CODE (decl) == TEMPLATE_DECL
&& VAR_OR_FUNCTION_DECL_P (DECL_TEMPLATE_RESULT (decl)));
- /* Ideally we would only warn in cases where there are no explicit
- instantiations of the template, but we don't currently track this
- in an easy-to-find way. */
+ /* Don't warn if we've seen any explicit instantiation definitions,
+ the intent might be for importers to only use those. */
+ if (template_has_explicit_inst (decl))
+ continue;
+
for (depset *rdep : dep->deps)
if (!rdep->is_binding () && rdep->is_tu_local ())
{
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index f36e0c954f4..d64d6df4f83 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -1657,11 +1657,14 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
if ((TREE_CODE (spec) == FUNCTION_DECL && DECL_NAMESPACE_SCOPE_P (spec)
&& PRIMARY_TEMPLATE_P (tmpl)
&& DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (tmpl)) == NULL_TREE)
+ || module_maybe_has_cmi_p ()
|| variable_template_p (tmpl))
/* If TMPL is a forward declaration of a template function, keep a list
of all specializations in case we need to reassign them to a friend
template later in tsubst_friend_function.
+ If we're building a CMI, keep a list for all function templates.
+
Also keep a list of all variable template instantiations so that
process_partial_specialization can check whether a later partial
specialization would have used it. */
diff --git a/gcc/testsuite/g++.dg/modules/internal-5_a.C b/gcc/testsuite/g++.dg/modules/internal-5_a.C
index c5ef3752f5a..be97ffa471a 100644
--- a/gcc/testsuite/g++.dg/modules/internal-5_a.C
+++ b/gcc/testsuite/g++.dg/modules/internal-5_a.C
@@ -27,7 +27,7 @@ export void function() {
internal_tmpl<int>();
}
-export template <typename T> void function_tmpl() { // { dg-warning "refers to TU-local entity" }
+export template <typename T> void function_tmpl() {
internal_t i {};
internal_tmpl_t<T> ii {};
internal_ovl(internal_x);
@@ -42,7 +42,7 @@ export int var
= (internal_t{}, internal_tmpl_t<int>{},
internal_ovl(internal_x), internal_tmpl<int>(), 0);
-export template <typename T> int var_tmpl // { dg-warning "refers to TU-local entity" }
+export template <typename T> int var_tmpl
= (internal_t{}, internal_tmpl_t<T>{},
internal_ovl(internal_x), internal_tmpl<T>(), 0);
--
2.47.1
From 03134a00bdc0f53cb30fde284808be71811e29e7 Mon Sep 17 00:00:00 2001
From: Jason Merrill <ja...@redhat.com>
Date: Wed, 11 Dec 2024 11:02:34 -0500
Subject: [PATCH] c++: adjust "Detect exposures of TU-local entities"
To: gcc-patches@gcc.gnu.org
This patch adjusts the handling of the injected-class-name to be the same as
the class name itself.
gcc/cp/ChangeLog:
* tree.cc (decl_linkage): Treat DECL_SELF_REFERENCE_P like
DECL_IMPLICIT_TYPEDEF_P.
* module.cc (depset::hash::is_tu_local_entity): Likewise.
(depset::hash::is_tu_local_value): Fix formatting.
---
gcc/cp/module.cc | 10 +++++-----
gcc/cp/tree.cc | 16 ++++++++--------
2 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 5d11e85f41d..823884e97f3 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -13247,10 +13247,11 @@ depset::hash::is_tu_local_entity (tree decl, bool explain/*=false*/)
{
gcc_checking_assert (DECL_P (decl));
- /* An explicit type alias is not an entity, and so is never TU-local. */
+ /* An explicit type alias is not an entity, and so is never TU-local.
+ Neither are the built-in declarations of 'int' and such. */
if (TREE_CODE (decl) == TYPE_DECL
- && !DECL_IMPLICIT_TYPEDEF_P (decl)
- && !DECL_SELF_REFERENCE_P (decl))
+ && (is_typedef_decl (decl)
+ || !OVERLOAD_TYPE_P (TREE_TYPE (decl))))
return false;
location_t loc = DECL_SOURCE_LOCATION (decl);
@@ -13348,7 +13349,6 @@ depset::hash::is_tu_local_entity (tree decl, bool explain/*=false*/)
these aren't really TU-local. */
if (TREE_CODE (decl) == TYPE_DECL
&& TYPE_ANON_P (type)
- && !DECL_SELF_REFERENCE_P (decl)
/* An enum with an enumerator name for linkage. */
&& !(UNSCOPED_ENUM_P (type) && TYPE_VALUES (type)))
{
@@ -13473,7 +13473,7 @@ depset::hash::is_tu_local_value (tree decl, tree expr, bool explain)
of reference type refer is TU-local and is usable in constant
expressions. */
if (TREE_CODE (e) == CONSTRUCTOR && AGGREGATE_TYPE_P (TREE_TYPE (e)))
- for (auto& f : CONSTRUCTOR_ELTS (e))
+ for (auto &f : CONSTRUCTOR_ELTS (e))
if (is_tu_local_value (decl, f.value, explain))
return true;
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 939d2b060fb..260c16418a1 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -5894,17 +5894,17 @@ decl_linkage (tree decl)
linkage first, and then transform that into a concrete
implementation. */
- /* An explicit type alias has no linkage. */
+ /* An explicit type alias has no linkage. Nor do the built-in declarations
+ of 'int' and such. */
if (TREE_CODE (decl) == TYPE_DECL
- && !DECL_IMPLICIT_TYPEDEF_P (decl)
- && !DECL_SELF_REFERENCE_P (decl))
+ && !DECL_IMPLICIT_TYPEDEF_P (decl))
{
- /* But this could be a typedef name for linkage purposes, in which
- case we're interested in the linkage of the main decl. */
- if (decl == TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (decl))))
- decl = TYPE_MAIN_DECL (TREE_TYPE (decl));
- else
+ if (is_typedef_decl (decl)
+ || !OVERLOAD_TYPE_P (TREE_TYPE (decl)))
return lk_none;
+ /* But this could be a typedef name for linkage purposes or injected
+ class name; look to the implicit typedef for linkage. */
+ decl = TYPE_MAIN_DECL (TREE_TYPE (decl));
}
/* Namespace-scope entities with no name usually have no linkage. */
--
2.47.1
From 019071d80d8f87b01a377429f2359b4623c096d6 Mon Sep 17 00:00:00 2001
From: Jason Merrill <ja...@redhat.com>
Date: Mon, 16 Dec 2024 21:21:13 -0500
Subject: [PATCH] c++: adjust "Validate external linkage definitions in header
units"
To: gcc-patches@gcc.gnu.org
Let's call decl_defined_p instead of duplicating the checks here.
gcc/cp/ChangeLog:
* decl.cc (grokfndecl): Simplify comment.
* module.cc (check_module_decl_linkage): Use decl_defined_p.
---
gcc/cp/decl.cc | 3 +--
gcc/cp/module.cc | 8 +++-----
2 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 291a54f8a37..5db684d860c 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -10979,8 +10979,7 @@ grokfndecl (tree ctype,
makes them more like a definition anyway. */
DECL_INITIAL (decl) = void_node;
/* But to ensure that external-linkage deduction guides in header units
- don't fall afoul of [module.import] p6, mark them as inline to give
- the same effect as them not having a definition. */
+ don't fall afoul of [module.import] p6, mark them as inline. */
DECL_DECLARED_INLINE_P (decl) = true;
break;
default:
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 629863e4007..aef911bbea5 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -20178,12 +20178,10 @@ check_module_decl_linkage (tree decl)
if (header_module_p ()
&& !processing_template_decl
&& ((TREE_CODE (decl) == FUNCTION_DECL
- && !DECL_DECLARED_INLINE_P (decl)
- && DECL_INITIAL (decl))
+ && !DECL_DECLARED_INLINE_P (decl))
|| (TREE_CODE (decl) == VAR_DECL
- && !DECL_INLINE_VAR_P (decl)
- && DECL_INITIALIZED_P (decl)
- && !DECL_IN_AGGR_P (decl)))
+ && !DECL_INLINE_VAR_P (decl)))
+ && decl_defined_p (decl)
&& !(DECL_LANG_SPECIFIC (decl)
&& DECL_TEMPLATE_INSTANTIATION (decl))
&& decl_linkage (decl) == lk_external)
--
2.47.1