{"id":2219713,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2219713/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/patch/adBResH2QvUpQzSE@Thaum.localdomain/","project":{"id":17,"url":"http://patchwork.ozlabs.org/api/1.1/projects/17/?format=json","name":"GNU Compiler Collection","link_name":"gcc","list_id":"gcc-patches.gcc.gnu.org","list_email":"gcc-patches@gcc.gnu.org","web_url":null,"scm_url":null,"webscm_url":null},"msgid":"<adBResH2QvUpQzSE@Thaum.localdomain>","date":"2026-04-03T23:47:06","name":"c++/modules: Fix installing a partial spec over an implicit inst [PR124732]","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"fec0943b555fb5eca7eee12454fadda0e222765b","submitter":{"id":85216,"url":"http://patchwork.ozlabs.org/api/1.1/people/85216/?format=json","name":"Nathaniel Shead","email":"nathanieloshead@gmail.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/gcc/patch/adBResH2QvUpQzSE@Thaum.localdomain/mbox/","series":[{"id":498685,"url":"http://patchwork.ozlabs.org/api/1.1/series/498685/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/list/?series=498685","date":"2026-04-03T23:47:06","name":"c++/modules: Fix installing a partial spec over an implicit inst [PR124732]","version":1,"mbox":"http://patchwork.ozlabs.org/series/498685/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2219713/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2219713/checks/","tags":{},"headers":{"Return-Path":"<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":["incoming@patchwork.ozlabs.org","gcc-patches@gcc.gnu.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","gcc-patches@gcc.gnu.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=DPk4tJMm;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=38.145.34.32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n\tdkim=pass (2048-bit key,\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=DPk4tJMm","sourceware.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com","sourceware.org; spf=pass smtp.mailfrom=gmail.com","server2.sourceware.org;\n arc=none smtp.remote-ip=209.85.214.181"],"Received":["from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fnb514p7dz1yCs\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 04 Apr 2026 10:47:44 +1100 (AEDT)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id D5F6B4BA23F0\n\tfor <incoming@patchwork.ozlabs.org>; Fri,  3 Apr 2026 23:47:41 +0000 (GMT)","from mail-pl1-f181.google.com (mail-pl1-f181.google.com\n [209.85.214.181])\n by sourceware.org (Postfix) with ESMTPS id 6E0B04BA23DB\n for <gcc-patches@gcc.gnu.org>; Fri,  3 Apr 2026 23:47:12 +0000 (GMT)","by mail-pl1-f181.google.com with SMTP id\n d9443c01a7336-2b240d753ceso5305105ad.3\n for <gcc-patches@gcc.gnu.org>; Fri, 03 Apr 2026 16:47:12 -0700 (PDT)","from Thaum.localdomain ([163.53.146.3])\n by smtp.gmail.com with ESMTPSA id\n 41be03b00d2f7-c76c6491fedsm6983220a12.8.2026.04.03.16.47.09\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Fri, 03 Apr 2026 16:47:10 -0700 (PDT)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org D5F6B4BA23F0","OpenDKIM Filter v2.11.0 sourceware.org 6E0B04BA23DB"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org 6E0B04BA23DB","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org 6E0B04BA23DB","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1775260032; cv=none;\n b=du6wvyBUGMsVNE8X4+jTqdeGwBSdAYBFTLIIzeZWJQ+gjayD7IELH94skHRi88PqWo5IWQDbnJpXoBGyn52f9raQ7o8jj82kSqQxbNFUAxSm2KsBJFdmgXLfPe7yAYBqWjko7RsNhAsKnZpTNkRiJ2ROJ5MboENWiNiDrcwUk/w=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1775260032; c=relaxed/simple;\n bh=/hqH0JMliV/AXUBDtkvhT5Wvf1QqBTd6HBepdAdVc9k=;\n h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version;\n b=ff2+luvqCQA1lfCHKmvI35wk2S7/egsEsnb7+eArpQM+CCtVquGOXoQ87fNMDCbOfVvu2RS0a3C/+SN9ZFwzvQS0X4ohCCQGxUhOUqFNrS+SEDXlqPnj+FG2UxQWc1UTwXCEassvk6EzPoF/Ecs1y4Kw1x/pCoRkOf/VMYAf4S4=","ARC-Authentication-Results":"i=1; server2.sourceware.org","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1775260031; x=1775864831; darn=gcc.gnu.org;\n h=content-disposition:mime-version:message-id:subject:cc:to:from:date\n :from:to:cc:subject:date:message-id:reply-to;\n bh=owpiHSMvuWwjGvmOVrpD3VvzBrSgxCoK4lJ6bicHos0=;\n b=DPk4tJMmVt4LzFtjyMHwskPfHgNMaFaMD+kSEKmmcxASW2hxnNVJ+ZeYi4lIRsXVFD\n 0VgtcX+EcOYpGgoHuXDfCcQ178/ru4QfMdh4K+VdItCeO8XwR7mN7mxvJxStw1ta16bE\n G1Q7VWb1cezKNH51zyucB0qVfocyBLh32aTzH5RmU8JtYDjiDjgXwso1DLPe3EY8iV4i\n dyn9aagrvtybb87r2JCWRUX5sMW/02mNGLV6kyu9LbBBYmATF0DYCiapgvUPm2YS44hD\n AcATSwTgzEHiwiA53k1rUrJPHzy5moMh897SEwf59nN7t4WiLXCPU+3iPveNbXeBZJiL\n jmHw==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1775260031; x=1775864831;\n h=content-disposition:mime-version:message-id:subject:cc:to:from:date\n :x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id\n :reply-to;\n bh=owpiHSMvuWwjGvmOVrpD3VvzBrSgxCoK4lJ6bicHos0=;\n b=XDv7OFqTNQDGeZaqD8VQtyIVqsAOhtSzuNpA6jZX0vT9A2vnHw2K5kgPrPd0awrPnC\n bYRULozUYVUbALmDomlWOW223Ix98taQ9SUfm0M0fS30Wt5GFogYGJQCv7n8n8VqS9jA\n rjxrQ7muGN5ySj51ynquLe561fBf1PtjJKBB4TwNWTJGzu1Xsl6fy2IzcSHuVtAFxJWq\n vkLhJ7VYBMvkDk8ubskgmq+yfDBEOSZKKWHFUQFd7uQfM1JhRxTW3hUQADreC6PxsUIB\n 4RaZ7WET+40cK2SnqH0lVhjUOYdEYvtbvOduKeQuF1qvQSbK9iE4t7whnU/bLQunUxXP\n yQBg==","X-Gm-Message-State":"AOJu0YwuJyuNz6F6RoHWjZ3hu7L6fDU0Sd9Vcb2UsotHeK2+J4pWFXwI\n ZeuPeZrzpdU6grK+aqoGa1K8yt0dDNmYNNI9QpD6Y9gLdIaolYzuOwsj99xpUw==","X-Gm-Gg":"ATEYQzw+U2hmeTnoHdmgOM6jkOk11zH0qWITqVaFJ38HBDxpWuBfbeljqivNx1xvChI\n TZg0X8knJHv+uGxULZ0+XCZolmSo4UlIwmytJnUs2Ei5e1NmTTzTncfL9T5l/DYw1bnPIcm9YXz\n CXMPMvpmK1v1RNt0VW8lJ9I4TaLpwh6Xtm4kX5J4gt1gflbwgC7yriJY+pTxVaPAU9/ajXRXo5H\n UD0x7LiWs1ySyhHpWK+isrhd4yq6X6oz1T03i/DEDVY9ZtpIxjRRM5i0lUAi70gi7nWQ1XpoWki\n J5z/jsorulky8sQ0T3ikJf+g5JJFxsmEr2Koh7advLQfwKmUDyWMI5SWHlKRPJ0kCfaWRfsirOO\n qsqVLF7K36LyxYL8jWMde1nS8/5ZdZ0jf7j40McMI7HnD2gqXNz7oRwYahUaF/1e671ADdvn4K1\n Ift8di7dU2YYigRQ4laaJmp0d1dGHhUTuuSbgzMVVJor6A","X-Received":"by 2002:a05:6a21:1b85:b0:39f:2a27:91b0 with SMTP id\n adf61e73a8af0-39f2f0a5ff4mr2585832637.6.1775260031006;\n Fri, 03 Apr 2026 16:47:11 -0700 (PDT)","Date":"Sat, 4 Apr 2026 10:47:06 +1100","From":"Nathaniel Shead <nathanieloshead@gmail.com>","To":"gcc-patches@gcc.gnu.org","Cc":"Jason Merrill <jason@redhat.com>","Subject":"[PATCH] c++/modules: Fix installing a partial spec over an implicit\n inst [PR124732]","Message-ID":"<adBResH2QvUpQzSE@Thaum.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","X-BeenThere":"gcc-patches@gcc.gnu.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Gcc-patches mailing list <gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>","List-Archive":"<https://gcc.gnu.org/pipermail/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-request@gcc.gnu.org?subject=help>","List-Subscribe":"<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>","Errors-To":"gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"},"content":"Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk/15?\n\n-- >8 --\n\nWe fail a checking-only assertion in the linked PR because we get a\nTEMPLATE_DECL that is marked as DECL_MODULE_ENTITY_P but we can't find\nits entry in the entity map.\n\nThe following sequence of events has occurred:\n\n1. A partial specialisation in the current TU is built.\n\n2. We import a pending instantiation (a TYPE_DECL); this matches the\n   partial specialisation, we register the existing TYPE_DECL on the\n   entity_map and mark as DECL_MODULE_ENTITY_P.\n\n3. We import a partial specialisation (a TEMPLATE_DECL); this matches\n   the same partial specialisation, but we attempt to register the\n   TEMPLATE_DECL.  We see that DECL_MODULE_ENTITY_P is already set\n   (we only store this on the DECL_TEMPLATE_RESULT) and so assume we\n   should be able to find it in the entity map, but it's not there.\n\nThis is similar to PR c++/120013, except in that case we had swapped\nsteps #2 and #3, so we attempted to recover the TEMPLATE_DECL of the\npartial spec; but I'd gotten it wrong and got the primary TEMPLATE_DECL\nrather than the partial one, though I haven't been able to find a way to\ncause a failure from that yet.\n\nOn reflection, I think r14-9881-g77c0b5b23f was wrong to mess around\nwith overriding entity_map to indicate partition imports that will need\nto be exported, as it seems to be quite fragile and I'm concerned there\nare more edge cases we haven't found yet.  So this patch instead\nintroduces a new DECL_MODULE_PARTITION_P flag to indicate entities\nimported from a module partition, and then make_dependency can check\nthis flag to determine what entities can be treated as imported.\n\n\tPR c++/124732\n\ngcc/cp/ChangeLog:\n\n\t* cp-tree.h (DECL_MODULE_PARTITION_P): New accessor.\n\t(struct lang_decl_base): New field 'module_partition_p'.\n\t* decl.cc (duplicate_decls): Handle DECL_MODULE_PARTITION_P.\n\t* lex.cc (cxx_dup_lang_specific_decl): Likewise.\n\t* module.cc (trees_in::install_entity): Just set\n\tDECL_MODULE_PARTITION_P rather than attempting to adjust\n\tentity_map.\n\t(depset::hash::make_dependency): Check DECL_MODULE_PARTITION_P\n\tinstead of from->remap for marking imported deps.\n\ngcc/testsuite/ChangeLog:\n\n\t* g++.dg/modules/partial-8_d.C: Supplement test.\n\nSigned-off-by: Nathaniel Shead <nathanieloshead@gmail.com>\n---\n gcc/cp/cp-tree.h                           |  7 ++-\n gcc/cp/decl.cc                             |  2 +\n gcc/cp/lex.cc                              |  1 +\n gcc/cp/module.cc                           | 56 ++++++----------------\n gcc/testsuite/g++.dg/modules/partial-8_d.C |  7 ++-\n 5 files changed, 29 insertions(+), 44 deletions(-)","diff":"diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h\nindex ea3cb049785..d5746af8b9a 100644\n--- a/gcc/cp/cp-tree.h\n+++ b/gcc/cp/cp-tree.h\n@@ -1848,6 +1848,10 @@ check_constraint_info (tree t)\n #define DECL_MODULE_IMPORT_P(NODE) \\\n   (DECL_LANG_SPECIFIC (DECL_MODULE_CHECK (NODE))->u.base.module_import_p)\n \n+/* True if this decl was seen from a partition.  */\n+#define DECL_MODULE_PARTITION_P(NODE) \\\n+  (DECL_LANG_SPECIFIC (DECL_MODULE_CHECK (NODE))->u.base.module_partition_p)\n+\n /* True if this decl is in the entity hash & array.  This means that\n    some variant was imported, even if DECL_MODULE_IMPORT_P is false.  */\n #define DECL_MODULE_ENTITY_P(NODE) \\\n@@ -3142,6 +3146,7 @@ struct GTY(()) lang_decl_base {\n   unsigned module_purview_p : 1;\t   /* in named-module purview */\n   unsigned module_attach_p : 1;\t\t   /* attached to named module */\n   unsigned module_import_p : 1;\t\t   /* from an import */\n+  unsigned module_partition_p : 1;\t   /* from a partition */\n   unsigned module_entity_p : 1;\t\t   /* is in the entitity ary & hash */\n \n   unsigned module_keyed_decls_p : 1;\t   /* has keys, applies to all decls */\n@@ -3149,7 +3154,7 @@ struct GTY(()) lang_decl_base {\n   /* VAR_DECL being used to represent an OpenMP declared mapper.  */\n   unsigned omp_declare_mapper_p : 1;\n \n-  /* 10 spare bits.  */\n+  /* 9 spare bits.  */\n };\n \n /* True for DECL codes which have template info and access.  */\ndiff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc\nindex 8409752aa0c..d5f7dfb765b 100644\n--- a/gcc/cp/decl.cc\n+++ b/gcc/cp/decl.cc\n@@ -3364,10 +3364,12 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)\n   /* Merge module entity mapping information.  */\n   if (DECL_LANG_SPECIFIC (olddecl)\n       && (DECL_MODULE_ENTITY_P (olddecl)\n+\t  || DECL_MODULE_PARTITION_P (olddecl)\n \t  || DECL_MODULE_KEYED_DECLS_P (olddecl)))\n     {\n       retrofit_lang_decl (newdecl);\n       DECL_MODULE_ENTITY_P (newdecl) = DECL_MODULE_ENTITY_P (olddecl);\n+      DECL_MODULE_PARTITION_P (newdecl) = DECL_MODULE_PARTITION_P (olddecl);\n       DECL_MODULE_KEYED_DECLS_P (newdecl) = DECL_MODULE_KEYED_DECLS_P (olddecl);\n     }\n \ndiff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc\nindex 88b0b24e097..135ded13047 100644\n--- a/gcc/cp/lex.cc\n+++ b/gcc/cp/lex.cc\n@@ -1111,6 +1111,7 @@ cxx_dup_lang_specific_decl (tree node)\n      (module_purview_p still does).  */\n   ld->u.base.module_entity_p = false;\n   ld->u.base.module_import_p = false;\n+  ld->u.base.module_partition_p = false;\n   ld->u.base.module_keyed_decls_p = false;\n \n   if (GATHER_STATISTICS)\ndiff --git a/gcc/cp/module.cc b/gcc/cp/module.cc\nindex 6958388e454..e2b28e80e51 100644\n--- a/gcc/cp/module.cc\n+++ b/gcc/cp/module.cc\n@@ -8284,38 +8284,10 @@ trees_in::install_entity (tree decl)\n       gcc_checking_assert (!existed);\n       slot = ident;\n     }\n-  else\n-    {\n-      unsigned *slot = entity_map->get (DECL_UID (decl));\n-\n-      /* The entity must be in the entity map already.  However, DECL may\n-\t be the DECL_TEMPLATE_RESULT of an existing partial specialisation\n-\t if we matched it while streaming another instantiation; in this\n-\t case we already registered that TEMPLATE_DECL.  */\n-      if (!slot)\n-\t{\n-\t  tree type = TREE_TYPE (decl);\n-\t  gcc_checking_assert (TREE_CODE (decl) == TYPE_DECL\n-\t\t\t       && CLASS_TYPE_P (type)\n-\t\t\t       && CLASSTYPE_TEMPLATE_SPECIALIZATION (type));\n-\t  slot = entity_map->get (DECL_UID (CLASSTYPE_TI_TEMPLATE (type)));\n-\t}\n-      gcc_checking_assert (slot);\n \n-      if (state->is_partition ())\n-\t{\n-\t  /* The decl is already in the entity map, but we see it again now\n-\t     from a partition: we want to overwrite if the original decl\n-\t     wasn't also from a (possibly different) partition.  Otherwise,\n-\t     for things like template instantiations, make_dependency might\n-\t     not realise that this is also provided from a partition and\n-\t     should be considered part of this module (and thus always\n-\t     emitted into the primary interface's CMI).  */\n-\t  module_state *imp = import_entity_module (*slot);\n-\t  if (!imp->is_partition ())\n-\t    *slot = ident;\n-\t}\n-    }\n+  /* Remember to treat this as-if declared in this module later.  */\n+  if (state->is_partition ())\n+    DECL_MODULE_PARTITION_P (not_tmpl) = true;\n \n   return true;\n }\n@@ -14648,23 +14620,23 @@ depset::hash::make_dependency (tree decl, entity_kind ek)\n \t  bool imported_from_module_p = false;\n \n \t  if (DECL_LANG_SPECIFIC (not_tmpl)\n-\t      && DECL_MODULE_IMPORT_P (not_tmpl))\n+\t      && DECL_MODULE_IMPORT_P (not_tmpl)\n+\t      /* Treat imports from partitions as part of the primary module.  */\n+\t      && (!DECL_MODULE_PARTITION_P (not_tmpl)\n+\t\t  || module_partition_p ()))\n \t    {\n \t      /* Store the module number and index in cluster/section,\n \t\t so we don't have to look them up again.  */\n \t      unsigned index = import_entity_index (decl);\n \t      module_state *from = import_entity_module (index);\n-\t      /* Remap will be zero for imports from partitions, which\n-\t\t we want to treat as-if declared in this TU.  */\n-\t      if (from->remap)\n-\t\t{\n-\t\t  dep->cluster = index - from->entity_lwm;\n-\t\t  dep->section = from->remap;\n-\t\t  dep->set_flag_bit<DB_IMPORTED_BIT> ();\n+\t      gcc_checking_assert (from->remap);\n \n-\t\t  if (!from->is_header ())\n-\t\t    imported_from_module_p = true;\n-\t\t}\n+\t      dep->cluster = index - from->entity_lwm;\n+\t      dep->section = from->remap;\n+\t      dep->set_flag_bit<DB_IMPORTED_BIT> ();\n+\n+\t      if (!from->is_header ())\n+\t\timported_from_module_p = true;\n \t    }\n \n \t  /* Check for TU-local entities.  This is unnecessary in header\ndiff --git a/gcc/testsuite/g++.dg/modules/partial-8_d.C b/gcc/testsuite/g++.dg/modules/partial-8_d.C\nindex 2aedb39670c..8df484cef11 100644\n--- a/gcc/testsuite/g++.dg/modules/partial-8_d.C\n+++ b/gcc/testsuite/g++.dg/modules/partial-8_d.C\n@@ -1,9 +1,14 @@\n // PR c++/120013\n-// { dg-additional-options \"-fmodules\" }\n+// PR c++/124732\n+// { dg-additional-options \"-fmodules -Wno-global-module\" }\n // { dg-module-cmi m }\n // Same as partial-8_c.C but in the other order, to ensure\n // that loading a partial spec over an instantiation works\n \n+module;\n+#include \"partial-8.h\"\n+template <typename T> struct tuple_element<T*>;\n+template <typename T> constexpr int var<T*> = 456;\n export module m;\n import :b;\n import :a;\n","prefixes":[]}