aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorNathaniel Shead <nathanieloshead@gmail.com>2025-04-29 17:31:55 +1000
committerNathaniel Shead <nathanieloshead@gmail.com>2025-05-01 09:50:20 +1000
commit22ccaded63e96e5a42f4e3676dbbb57aa05b36f9 (patch)
treebe5968436bbd57075b1bc594a34888bacd4ea22e /gcc
parent299d48ff4a34c00a6ef964b694fb9b1312683049 (diff)
downloadgcc-22ccaded63e96e5a42f4e3676dbbb57aa05b36f9.zip
gcc-22ccaded63e96e5a42f4e3676dbbb57aa05b36f9.tar.gz
gcc-22ccaded63e96e5a42f4e3676dbbb57aa05b36f9.tar.bz2
c++/modules: Catch exposures of TU-local values through inline references [PR119996]
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 <nathanieloshead@gmail.com> Reviewed-by: Jason Merrill <jason@redhat.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/module.cc27
-rw-r--r--gcc/testsuite/g++.dg/modules/internal-13.C33
2 files changed, 53 insertions, 7 deletions
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index a2e0d6d..7e3b24e 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 0000000..ce1454e
--- /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