Bootstrapped and regtested on x86_64-pc-linux-gnu (so far just
modules.exp), OK for trunk and 15 if full regtest succeeds?

-- >8 --

In r15-9136-g0210bedf481a9f we started erroring for inline variables
that exposed TU-local entities in their definition, as such variables
would need to have their definitions emitted in importers but would not
know about the TU-local entities they referenced.

A case we mised was potentially-constant references, which disable
streaming of their definitions in make_dependency so as to comply with
[expr.const] p9.2.  This meant that we didn't see the definition
referencing a TU-local entity, leading to nonsensical results.

        PR c++/119551
        PR c++/119996

gcc/cp/ChangeLog:

        * module.cc (depset::hash::make_dependency): Also mark inline
        variables referencing TU-local values as exposures here.
        (depset::hash::finalize_dependencies): Add error message for
        inline variables.

gcc/testsuite/ChangeLog:

        * g++.dg/modules/internal-13.C: New test.

Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
---
 gcc/cp/module.cc                           | 27 +++++++++++++-----
 gcc/testsuite/g++.dg/modules/internal-13.C | 33 ++++++++++++++++++++++
 2 files changed, 53 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/internal-13.C

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index a2e0d6d2571..7e3b24e2e42 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -14062,9 +14062,10 @@ depset::hash::make_dependency (tree decl, entity_kind 
ek)
                     streaming the definition in such cases.  */
                  dep->clear_flag_bit<DB_DEFN_BIT> ();
 
-                 if (DECL_DECLARED_CONSTEXPR_P (decl))
-                   /* Also, a constexpr variable initialized to a TU-local
-                      value is an exposure.  */
+                 if (DECL_DECLARED_CONSTEXPR_P (decl)
+                     || DECL_INLINE_VAR_P (decl))
+                   /* A constexpr variable initialized to a TU-local value,
+                      or an inline value (PR c++/119996), is an exposure.  */
                    dep->set_flag_bit<DB_EXPOSURE_BIT> ();
                }
            }
@@ -15025,12 +15026,24 @@ depset::hash::finalize_dependencies ()
                break;
              }
 
-         if (!explained && VAR_P (decl) && DECL_DECLARED_CONSTEXPR_P (decl))
+         if (!explained
+             && VAR_P (decl)
+             && (DECL_DECLARED_CONSTEXPR_P (decl)
+                 || DECL_INLINE_VAR_P (decl)))
            {
              auto_diagnostic_group d;
-             error_at (DECL_SOURCE_LOCATION (decl),
-                       "%qD is declared %<constexpr%> and is initialized to "
-                       "a TU-local value", decl);
+             if (DECL_DECLARED_CONSTEXPR_P (decl))
+               error_at (DECL_SOURCE_LOCATION (decl),
+                         "%qD is declared %<constexpr%> and is initialized to "
+                         "a TU-local value", decl);
+             else
+               {
+                 /* This can only occur with references.  */
+                 gcc_checking_assert (TYPE_REF_P (TREE_TYPE (decl)));
+                 error_at (DECL_SOURCE_LOCATION (decl),
+                           "%qD is a reference declared %<inline%> and is "
+                           "constant-initialized to a TU-local value", decl);
+               }
              bool informed = is_tu_local_value (decl, DECL_INITIAL (decl),
                                                 /*explain=*/true);
              gcc_checking_assert (informed);
diff --git a/gcc/testsuite/g++.dg/modules/internal-13.C 
b/gcc/testsuite/g++.dg/modules/internal-13.C
new file mode 100644
index 00000000000..ce1454e17bc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/internal-13.C
@@ -0,0 +1,33 @@
+// PR c++/119996
+// { dg-additional-options "-fmodules" }
+// { dg-module-cmi !M }
+// Similar to internal-11.C, but for potentially-constant variables.
+
+export module M;
+
+static int tu_local = 5;
+static int& foo() { return tu_local; }
+
+// For implementation reasons, we adjust [basic.link] p14.2 to restrict ignored
+// exposures to non-inline variables, since for inline variables without
+// dynamic initialisation we need to emit their initialiser for importer use.
+
+int& a = tu_local;  // OK
+inline int& b = tu_local;  // { dg-error "initialized to a TU-local value" }
+inline auto& bf = foo;  // { dg-error "initialized to a TU-local value" }
+
+// But dynamic initialisers are fine, importers will just treat them as 
external.
+inline int& c = foo();  // OK
+
+// For consistency, we follow the same rules with templates, noting that
+// we still need to emit definitions with dynamic initializers so we error.
+template <typename T> int& d = tu_local;  // OK
+template <typename T> inline int& e = tu_local;  // { dg-error "exposes 
TU-local entity" }
+template <typename T> inline int& f = foo();  // { dg-error "exposes TU-local 
entity" }
+template <typename T> inline auto& ff = foo;  // { dg-error "exposes TU-local 
entity" }
+
+// Note that non-references are OK, because an integer or enumeration
+// value is never TU-local: we fold these expressions early
+// (as we should, by [basic.link] p14.4).
+static const int const_val = 123;
+inline const int potentially_constant = const_val;  // OK
-- 
2.47.0

Reply via email to