void
trees_out::write_var_def (tree decl)
{
- /* The initializer of a variable or variable template is ignored for
- determining exposures. */
- auto ovr = make_temp_override (dep_hash->ignore_tu_local, VAR_P (decl));
+ /* The initializer of a non-inline variable or variable template is
+ ignored for determining exposures. */
+ auto ovr = make_temp_override (dep_hash->ignore_tu_local,
+ VAR_P (decl) && !DECL_INLINE_VAR_P (decl));
tree init = DECL_INITIAL (decl);
tree_node (init);
--- /dev/null
+// PR c++/119551
+// { dg-additional-options "-fmodules" }
+// { dg-module-cmi !M }
+
+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 "exposes TU-local entity" }
+
+// 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" }
--- /dev/null
+// PR c++/119551
+// { dg-additional-options "-fmodules" }
+// { dg-module-cmi M }
+// Test that emitting variables referencing TU-local entities
+// builds and runs correctly.
+
+export module M;
+
+static int tu_local_var = 5;
+static int* tu_local_func() { return &tu_local_var; }
+
+export int* a = &tu_local_var;
+export inline int* b = tu_local_func();
--- /dev/null
+// PR c++/119551
+// { dg-module-do run }
+// { dg-additional-options "-fmodules" }
+
+import M;
+
+int main() {
+ if (*a != 5)
+ __builtin_abort();
+ if (*b != 5)
+ __builtin_abort();
+ if (a != b)
+ __builtin_abort();
+}
template <> void function_tmpl<ok_inst_tag*>() {}
-// The initializer for a variable or variable template
+// The initializer for a (non-inline) variable or variable template
export int var
= (internal_t{}, internal_tmpl_t<int>{},
internal_ovl(internal_x), internal_tmpl<int>(), 0);
template int var_tmpl<ok_inst_tag>;
template <> int var_tmpl<ok_inst_tag*> = 0;
+export int* ptr = &internal_x;
+export template <typename T> int* ptr_tmpl = &internal_x; // { dg-warning "refers to TU-local entity" }
+
export int& constant_ref = internal_x;
static_assert (&constant_ref == &internal_x);
+// Support exposures in inline vars with dynamic initialisers
+export inline int dynamic_var = (internal_ovl(internal_x), 0);
+
// Friend declarations in a class definition
export struct klass { // { dg-bogus "TU-local" }
function_tmpl<ok_inst_tag*>();
int b = var_tmpl<ok_inst_tag>;
int c = var_tmpl<ok_inst_tag*>;
+ int d = *ptr;
+ int e = dynamic_var;
// But don't ignore exposures in these cases
function_tmpl<int>(); // { dg-message "required from here" }
int x = var_tmpl<int>; // { dg-message "required from here" }
int y = var_tmpl<int*>; // { dg-message "required from here" }
+ int z = *ptr_tmpl<int>; // { dg-message "required from here" }
// And decls initialized to a TU-local value are not constant here
// Unfortunately the error does not currently point to this decl
// { dg-error "is not a constant expression" "" { target *-*-* } 0 }
}
+// The errors occur in a different file, so we just test that all the
+// needed "required from here"s are found above.
// { dg-error "instantiation exposes TU-local entity" "" { target *-*-* } 0 }
+// { dg-bogus "required from here" "" { target *-*-* } 0 }