This patch series implements most of the changes made by P1815.  It also
cleans up a few bugs found along the way that impacted tests I wrote.

The whole patch series was bootstrapped on x86_64-pc-linux-gnu and
aarch64-unknown-linux-gnu with no regressions.

A range-diff against v2 is attached; the main changes are responses to
comments left on previous versions of this patch series.

Nathaniel Shead (5):
  c++/modules: Detect exposures of TU-local entities
  c++/modules: Ignore TU-local entities where necessary
  c++/modules: Support unnamed namespaces in header units
  c++/modules: Check linkage for exported declarations
  c++/modules: Validate external linkage definitions in header units
    [PR116401]

 gcc/c-family/c.opt                            |   4 +
 gcc/cp/cp-objcp-common.cc                     |   1 +
 gcc/cp/cp-tree.def                            |   6 +
 gcc/cp/cp-tree.h                              |  22 +-
 gcc/cp/decl.cc                                |   4 +
 gcc/cp/decl2.cc                               |   1 +
 gcc/cp/module.cc                              | 749 +++++++++++++++---
 gcc/cp/name-lookup.cc                         |  30 +-
 gcc/cp/name-lookup.h                          |   2 +-
 gcc/cp/parser.cc                              |   9 +-
 gcc/cp/pt.cc                                  | 100 ++-
 gcc/doc/invoke.texi                           |  19 +-
 gcc/testsuite/g++.dg/modules/block-decl-2.C   |   2 +-
 gcc/testsuite/g++.dg/modules/export-3.C       |   2 +-
 gcc/testsuite/g++.dg/modules/export-6.C       |  35 +
 gcc/testsuite/g++.dg/modules/hdr-2.H          | 172 ++++
 gcc/testsuite/g++.dg/modules/internal-1.C     |  15 +-
 gcc/testsuite/g++.dg/modules/internal-3.C     |  18 +
 gcc/testsuite/g++.dg/modules/internal-4_a.H   |   4 +
 gcc/testsuite/g++.dg/modules/internal-4_b.C   | 124 +++
 gcc/testsuite/g++.dg/modules/internal-5_a.C   | 110 +++
 gcc/testsuite/g++.dg/modules/internal-5_b.C   |  30 +
 gcc/testsuite/g++.dg/modules/internal-6.C     |  24 +
 gcc/testsuite/g++.dg/modules/internal-7_a.C   |  75 ++
 gcc/testsuite/g++.dg/modules/internal-7_b.C   |  21 +
 gcc/testsuite/g++.dg/modules/internal-8_a.C   |  35 +
 gcc/testsuite/g++.dg/modules/internal-9_a.H   |  28 +
 gcc/testsuite/g++.dg/modules/internal-9_b.C   |  29 +
 gcc/testsuite/g++.dg/modules/linkage-2.C      |   5 +-
 gcc/testsuite/g++.dg/modules/macro-4_c.H      |   2 +-
 gcc/testsuite/g++.dg/modules/pr106761.h       |   2 +-
 gcc/testsuite/g++.dg/modules/pr98843_b.H      |   2 +-
 gcc/testsuite/g++.dg/modules/pr99468.H        |   2 +-
 gcc/testsuite/g++.dg/modules/pragma-1_a.H     |   2 +-
 gcc/testsuite/g++.dg/modules/tpl-ary-1.h      |   2 +-
 .../g++.dg/modules/xtreme-header-8.C          |   8 +
 libcc1/libcp1plugin.cc                        |   2 +-
 37 files changed, 1555 insertions(+), 143 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/export-6.C
 create mode 100644 gcc/testsuite/g++.dg/modules/hdr-2.H
 create mode 100644 gcc/testsuite/g++.dg/modules/internal-3.C
 create mode 100644 gcc/testsuite/g++.dg/modules/internal-4_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/internal-4_b.C
 create mode 100644 gcc/testsuite/g++.dg/modules/internal-5_a.C
 create mode 100644 gcc/testsuite/g++.dg/modules/internal-5_b.C
 create mode 100644 gcc/testsuite/g++.dg/modules/internal-6.C
 create mode 100644 gcc/testsuite/g++.dg/modules/internal-7_a.C
 create mode 100644 gcc/testsuite/g++.dg/modules/internal-7_b.C
 create mode 100644 gcc/testsuite/g++.dg/modules/internal-8_a.C
 create mode 100644 gcc/testsuite/g++.dg/modules/internal-9_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/internal-9_b.C
 create mode 100644 gcc/testsuite/g++.dg/modules/xtreme-header-8.C

Range-diff against v2:
1:  4a032de3f30 ! 1:  36b944bfe8c c++/modules: Detect exposures of TU-local 
entities
    @@ Commit message
         follow-up patch for easier review, as it has broader implications for
         streaming.
     
    +    TU-local lambdas are also not yet properly implemented, due to other
    +    bugs with regards to LAMBDA_TYPE_EXTRA_SCOPE not being set in all cases
    +    that it probably should be (see also PR c++/116568).  We can revisit
    +    this once that issue has been fixed.
    +
         Finally, this patch makes a couple of small adjustments to the modules
         streaming logic to prune any leftover TU-local deps (that aren't
         erroneous exposures).  This is required for this patch to ensure that
    @@ Commit message
     
         gcc/cp/ChangeLog:
     
    -            * cp-tree.h (TYPE_DEPENDENT_P_VALID): Fix whitespace.
    -            (TYPE_DEFINED_IN_INITIALIZER_P): New accessor.
                 * module.cc (DB_IS_INTERNAL_BIT): Rename to...
                 (DB_TU_LOCAL_BIT): ...this.
                 (DB_REFS_INTERNAL_BIT): Rename to...
    @@ Commit message
                 diagnostic messages to report exposures of TU-local entities.
                 (depset::tarjan::connect): Don't include any TU-local depsets.
                 (depset::hash::connect): Likewise.
    -            (trees_out::core_bools): Stream TYPE_LANG_FLAG_7.
    -            (trees_in::core_bools): Read it.
    -            * parser.h (struct cp_parser::in_initializer_p): New flag.
    -            * parser.cc (cp_debug_parser): Print the new flag.
    -            (cp_parser_new): Set the new flag to false.
    -            (cp_parser_lambda_expression): Mark whether the lambda was
    -            defined in an initializer.
    -            (cp_parser_initializer): Set the new flag to true while 
parsing.
    -            (cp_parser_class_head): Mark whether the class was defined in 
an
    -            initializer.
    -            (cp_parser_concept_definition): Set the new flag to true while
    -            parsing.
     
         gcc/testsuite/ChangeLog:
     
    @@ Commit message
                 * g++.dg/modules/linkage-2.C: Adjust messages, remove XFAILS.
                 * g++.dg/modules/internal-3.C: New test.
                 * g++.dg/modules/internal-4_a.H: New test.
    -            * g++.dg/modules/internal-4_a.C: New test.
    +            * g++.dg/modules/internal-4_b.C: New test.
     
         Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
    -
    - ## gcc/cp/cp-tree.h ##
    -@@ gcc/cp/cp-tree.h: extern GTY(()) tree cp_global_trees[CPTI_MAX];
    -       AUTO_IS_DECLTYPE (in TEMPLATE_TYPE_PARM)
    -       TEMPLATE_TEMPLATE_PARM_SIMPLE_P (in TEMPLATE_TEMPLATE_PARM)
    -    6: TYPE_DEPENDENT_P_VALID
    -+   7: TYPE_DEFINED_IN_INITIALIZER_P
    - 
    -    Usage of DECL_LANG_FLAG_?:
    -    0: DECL_TEMPLATE_PARM_P (in PARM_DECL, CONST_DECL, TYPE_DECL, or 
TEMPLATE_DECL)
    -@@ gcc/cp/cp-tree.h: enum languages { lang_c, lang_cplusplus };
    - 
    - /* True if dependent_type_p has been called for this type, with the
    -    result that TYPE_DEPENDENT_P is valid.  */
    --#define TYPE_DEPENDENT_P_VALID(NODE) TYPE_LANG_FLAG_6(NODE)
    -+#define TYPE_DEPENDENT_P_VALID(NODE) TYPE_LANG_FLAG_6 (NODE)
    -+
    -+/* True if this type was defined in an initializer.  Used for determining
    -+   whether an entity is TU-local.  */
    -+#define TYPE_DEFINED_IN_INITIALIZER_P(NODE) TYPE_LANG_FLAG_7 (NODE)
    - 
    - /* Nonzero if this type is const-qualified.  */
    - #define CP_TYPE_CONST_P(NODE)                             \
    +    Reviewed-by: Jason Merrill <ja...@redhat.com>
     
      ## gcc/cp/module.cc ##
     @@ gcc/cp/module.cc: private:
    @@ gcc/cp/module.cc: public:
        private:
          static bool add_binding_entity (tree, WMB_Flags, void *);
      
    -@@ gcc/cp/module.cc: trees_out::core_bools (tree t, bits_out& bits)
    -       WB (t->type_common.lang_flag_4);
    -       WB (t->type_common.lang_flag_5);
    -       WB (t->type_common.lang_flag_6);
    -+      WB (t->type_common.lang_flag_7);
    -       WB (t->type_common.typeless_storage);
    -     }
    - 
    -@@ gcc/cp/module.cc: trees_in::core_bools (tree t, bits_in& bits)
    -       RB (t->type_common.lang_flag_4);
    -       RB (t->type_common.lang_flag_5);
    -       RB (t->type_common.lang_flag_6);
    -+      RB (t->type_common.lang_flag_7);
    -       RB (t->type_common.typeless_storage);
    -     }
    - 
     @@ gcc/cp/module.cc: depset::hash::find_binding (tree ctx, tree name)
        return slot ? *slot : NULL;
      }
    @@ gcc/cp/module.cc: depset::hash::find_binding (tree ctx, tree name)
     +     is used to declare only TU-local entities.
     +
     +     We consider types with names for linkage purposes as having names, 
since
    -+     these aren't really TU-local, and also consider 
constraint-expressions
    -+     as initializers.  */
    ++     these aren't really TU-local.  */
     +  if (TREE_CODE (decl) == TYPE_DECL
     +      && TYPE_ANON_P (type)
     +      && !DECL_SELF_REFERENCE_P (decl)
    @@ gcc/cp/module.cc: depset::hash::find_binding (tree ctx, tree name)
     +      && !(UNSCOPED_ENUM_P (type) && TYPE_VALUES (type)))
     +    {
     +      tree main_decl = TYPE_MAIN_DECL (type);
    -+      if (!TYPE_DEFINED_IN_INITIALIZER_P (type)
    -+    && !DECL_CLASS_SCOPE_P (main_decl)
    -+    && !decl_function_context (main_decl))
    ++      if (!DECL_CLASS_SCOPE_P (main_decl)
    ++    && !decl_function_context (main_decl)
    ++    /* FIXME: Lambdas defined outside initializers.  We'll need to more
    ++       thoroughly set LAMBDA_TYPE_EXTRA_SCOPE to check this.  */
    ++    && !LAMBDA_TYPE_P (type))
     +  {
     +    if (explain)
     +      inform (loc, "%qT has no name and is not defined within a class, "
    @@ gcc/cp/module.cc: module_state::write_begin (elf_out *to, cpp_reader 
*reader,
      #endif
      
     -  /* Determine Strongy Connected Components.  */
    -+  /* Determine Strongy Connected Components.  This will also strip any
    ++  /* Determine Strongly Connected Components.  This will also strip any
     +     unnecessary dependencies on imported or TU-local entities.  */
        vec<depset *> sccs = table.connect ();
      
        vec_alloc (ool, modules->length ());
     
    - ## gcc/cp/parser.cc ##
    -@@ gcc/cp/parser.cc: cp_debug_parser (FILE *file, cp_parser *parser)
    -                         parser->in_unbraced_export_declaration_p);
    -   cp_debug_print_flag (file, "Parsing a declarator",
    -                         parser->in_declarator_p);
    -+  cp_debug_print_flag (file, "Parsing an initializer",
    -+                        parser->in_initializer_p);
    -   cp_debug_print_flag (file, "In template argument list",
    -                         parser->in_template_argument_list_p);
    -   cp_debug_print_flag (file, "Parsing an iteration statement",
    -@@ gcc/cp/parser.cc: cp_parser_new (cp_lexer *lexer)
    -   /* We are not processing a declarator.  */
    -   parser->in_declarator_p = false;
    - 
    -+  /* We are not processing an initializer.  */
    -+  parser->in_initializer_p = false;
    -+
    -   /* We are not processing a template-argument-list.  */
    -   parser->in_template_argument_list_p = false;
    - 
    -@@ gcc/cp/parser.cc: cp_parser_lambda_expression (cp_parser* parser)
    - 
    -   record_lambda_scope (lambda_expr);
    -   record_lambda_scope_discriminator (lambda_expr);
    -+  TYPE_DEFINED_IN_INITIALIZER_P (type) = parser->in_initializer_p;
    - 
    -   /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set.  */
    -   determine_visibility (TYPE_NAME (type));
    -@@ gcc/cp/parser.cc: cp_parser_initializer (cp_parser *parser, bool 
*is_direct_init /*=nullptr*/,
    -   if (non_constant_p)
    -     *non_constant_p = false;
    - 
    -+  bool saved_in_initializer_p = parser->in_initializer_p;
    -+  parser->in_initializer_p = true;
    -+
    -   if (token->type == CPP_EQ)
    -     {
    -       /* Consume the `='.  */
    -@@ gcc/cp/parser.cc: cp_parser_initializer (cp_parser *parser, bool 
*is_direct_init /*=nullptr*/,
    -   if (!subexpression_p && check_for_bare_parameter_packs (init))
    -     init = error_mark_node;
    - 
    -+  parser->in_initializer_p = saved_in_initializer_p;
    -+
    -   return init;
    - }
    - 
    -@@ gcc/cp/parser.cc: cp_parser_class_head (cp_parser* parser,
    -     }
    -   else if (type == error_mark_node)
    -     type = NULL_TREE;
    -+  else
    -+    TYPE_DEFINED_IN_INITIALIZER_P (type) = parser->in_initializer_p;
    - 
    -   if (type)
    -     {
    -@@ gcc/cp/parser.cc: cp_parser_concept_definition (cp_parser *parser)
    -     }
    - 
    -   processing_constraint_expression_sentinel parsing_constraint;
    -+  parser->in_initializer_p = true;
    -+
    -   tree init = cp_parser_constraint_expression (parser);
    -   if (init == error_mark_node)
    -     cp_parser_skip_to_end_of_statement (parser);
    -@@ gcc/cp/parser.cc: cp_parser_concept_definition (cp_parser *parser)
    -      but continue as if it were.  */
    -   cp_parser_consume_semicolon_at_end_of_statement (parser);
    - 
    -+  parser->in_initializer_p = false;
    -   return finish_concept_definition (id, init, attrs);
    - }
    - 
    -
    - ## gcc/cp/parser.h ##
    -@@ gcc/cp/parser.h: struct GTY(()) cp_parser {
    -      direct-declarator.  */
    -   bool in_declarator_p;
    - 
    -+  /* TRUE if we are parsing an initializer.  */
    -+  bool in_initializer_p;
    -+
    -   /* TRUE if we are presently parsing a template-argument-list.  */
    -   bool in_template_argument_list_p;
    - 
    -
      ## gcc/testsuite/g++.dg/modules/block-decl-2.C ##
     @@ gcc/testsuite/g++.dg/modules/block-decl-2.C: export extern "C++" auto 
foo() {
        struct X {
    @@ gcc/testsuite/g++.dg/modules/internal-4_b.C (new)
     +auto in_initializer = []{};  // OK
     +
     +#if __cplusplus >= 202002L
    -+decltype([]{}) d_lambda;  // { dg-error "exposes TU-local entity" "" { 
target c++20 } }
    ++decltype([]{}) d_lambda;  // { dg-error "exposes TU-local entity" "" { 
xfail *-*-* } }
     +
     +template <typename T>
     +concept in_constraint_expression = requires {
     +  // Strictly by the standard this is currently ill-formed
     +  // (this is a constraint-expression not an initializer)
     +  // but I don't think that is intended.
    -+  []{};  // OK?
    ++  []{};  // { dg-bogus "exposes TU-local entity" }
     +};
     +#endif
     +
2:  597f0448531 ! 2:  b4e1e0e150f c++/modules: Implement ignored TU-local 
exposures
    @@ Metadata
     Author: Nathaniel Shead <nathanielosh...@gmail.com>
     
      ## Commit message ##
    -    c++/modules: Implement ignored TU-local exposures
    +    c++/modules: Ignore TU-local entities where necessary
     
         [basic.link] p14 lists a number of circumstances where a declaration
         naming a TU-local entity is not an exposure, notably the bodies of
    @@ Commit message
         prevent complicating the logic; I imagine this shouldn't ever come up
         though.
     
    -    We also add a new warning, '-Wignored-exposures', to handle the case
    -    where someone accidentally refers to a TU-local value from within a
    +    We also add a new warning, '-Wtemplate-names-tu-local', to handle the
    +    case where someone accidentally refers to a TU-local value from within 
a
         non-inline function template.  This will compile without errors as-is,
         but any attempt to instantiate the decl will fail; this warning can be
         used to ensure that this doesn't happen.  Unfortunately the warning has
    @@ Commit message
         instead just keeps the current (wrong) behaviour of non-exported
         entities not being visible to ADL at all.
     
    +    Additionally, this patch doesn't attempt to ignore non-ODR uses of
    +    constants in constexpr functions or templates.  The obvious approach of
    +    folding them early in 'mark_use' doesn't seem to work (for a variety of
    +    reasons), so this leaves this to a later patch to implement, as it's at
    +    least no worse than the current behaviour and easy enough to 
workaround.
    +
    +    For completeness this patch adds a new xtreme-header testcase to ensure
    +    that we have no regressions with regards to exposures of TU-local
    +    declarations in the standard library header files.  A more restrictive
    +    test would be to do 'export extern "C++"' here, but unfortunately the
    +    system headers on some targets declare TU-local entities, so we'll make
    +    do with checking that at least the C++ standard library headers don't
    +    refer to such entities.
    +
         gcc/c-family/ChangeLog:
     
    -            * c.opt: New warning '-Wignored-exposures'.
    +            * c.opt: New warning '-Wtemplate-names-tu-local'.
     
         gcc/cp/ChangeLog:
     
    @@ Commit message
                 (TU_LOCAL_ENTITY_LOCATION): New accessor.
                 (enum cp_tree_node_structure_enum): Add TS_CP_TU_LOCAL_ENTITY.
                 (union GTY): Add tu_local_entity field.
    -            * module.cc (enum tree_tag): New flag DB_IGNORED_EXPOSURE_BIT.
    -            (depset::is_ignored_exposure): New accessor.
    +            * module.cc (enum tree_tag): New flag DB_REFS_TU_LOCAL_BIT.
                 (depset::has_defn): Override for TU-local entities.
    -            (depset::hash::ignore_exposure): New field.
    +            (depset::refs_tu_local): New accessor.
    +            (depset::hash::ignore_tu_local): New field.
                 (depset::hash::hash): Initialize it.
                 (trees_out::tree_tag::tt_tu_local): New flag.
                 (trees_out::writing_local_entities): New field.
    @@ Commit message
                 (trees_out::find_tu_local_decl): New function.
                 (trees_out::tree_node): Intercept TU-local entities and write
                 placeholder values for them instead of normal streaming.
    -            (trees_in::tree_node): Read TU-local entities; handle TU-local
    +            (trees_in::tree_node): Handle TU-local entities and TU-local
                 template results.
                 (trees_out::write_function_def): Ignore exposures in non-inline
                 function bodies.
    @@ Commit message
                 (trees_in::read_class_def): Skip TU-local friends.
                 (trees_out::write_definition): Record whether we're writing a
                 decl which refers to TU-local entities.
    -            (depset::hash::add_dependency): Handle ignored exposures.
    +            (depset::hash::add_dependency): Only mark as exposure if we're 
not
    +            ignoring TU-local entities.
                 (depset::hash::find_dependencies): Use depset's own 
is_key_order
                 function rather than delegating via walker.  Pass whether the
                 decl has ignored TU-local entities in its definition.
                 (depset::hash::finalize_dependencies): Implement new warning
    -            Wignored-exposures.
    +            Wtemplate-names-tu-local.
                 (module_state::intercluster_seed): Don't seed TU-local deps.
                 (module_state::write_cluster): Pass whether the decl has 
ignored
                 TU-local entities in its definition.
    @@ Commit message
     
         gcc/ChangeLog:
     
    -            * doc/invoke.texi: Document -Wignored-exposures.
    +            * doc/invoke.texi: Document -Wtemplate-names-tu-local.
     
         gcc/testsuite/ChangeLog:
     
    @@ Commit message
                 * g++.dg/modules/internal-6.C: New test.
                 * g++.dg/modules/internal-7_a.C: New test.
                 * g++.dg/modules/internal-7_b.C: New test.
    +            * g++.dg/modules/internal-8_a.C: New test.
    +            * g++.dg/modules/xtreme-header-8.C: New test.
     
         Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
    +    Reviewed-by: Jason Merrill <ja...@redhat.com>
     
      ## gcc/c-family/c.opt ##
    -@@ gcc/c-family/c.opt: Wif-not-aligned
    - C ObjC C++ ObjC++ Var(warn_if_not_aligned) Init(1) Warning
    - Warn when the field in a struct is not aligned.
    +@@ gcc/c-family/c.opt: Wtemplate-id-cdtor
    + C++ ObjC++ Var(warn_template_id_cdtor) Warning
    + Warn about simple-template-id in a constructor or destructor.
      
    -+Wignored-exposures
    -+C++ ObjC++ Var(warn_ignored_exposures) Warning EnabledBy(Wextra)
    -+Warn about ignored exposures of TU-local entities in a module.
    ++Wtemplate-names-tu-local
    ++C++ ObjC++ Var(warn_template_names_tu_local) Warning EnabledBy(Wextra)
    ++Warn about templates naming TU-local entities in a module.
     +
    - Wignored-qualifiers
    - C C++ Var(warn_ignored_qualifiers) Warning EnabledBy(Wextra)
    - Warn whenever type qualifiers are ignored.
    + Wterminate
    + C++ ObjC++ Warning Var(warn_terminate) Init(1)
    + Warn if a throw expression will always result in a call to terminate().
     
      ## gcc/cp/cp-objcp-common.cc ##
     @@ gcc/cp/cp-objcp-common.cc: cp_tree_size (enum tree_code code)
    @@ gcc/cp/cp-tree.h: check_constraint_info (tree t)
         it for unscoped enums.  */
      #define DECL_MODULE_EXPORT_P(NODE) TREE_LANG_FLAG_3 (NODE)
      
    -+/* Represents a streamed-in translation-unit-local entity. Any use of this
    -+   should emit an error.  */
    ++/* Represents a streamed-in translation-unit-local entity.  Any use of
    ++   this node when instantiating a template should emit an error.  */
     +struct GTY(()) tree_tu_local_entity {
     +  struct tree_base base;
     +  tree name;
     +  location_t loc;
     +};
     +
    -+/* The name of a translation-unit local-entity.  */
    ++/* The name of a translation-unit-local entity.  */
     +#define TU_LOCAL_ENTITY_NAME(NODE) \
     +  (((struct tree_tu_local_entity *)TU_LOCAL_ENTITY_CHECK (NODE))->name)
     +
    @@ gcc/cp/cp-tree.h: union GTY((desc ("cp_tree_node_structure (&%h)"),
     
      ## gcc/cp/module.cc ##
     @@ gcc/cp/module.cc: private:
    +     DB_KIND_BITS = EK_BITS,
    +     DB_DEFN_BIT = DB_KIND_BIT + DB_KIND_BITS,
          DB_IS_MEMBER_BIT,             /* Is an out-of-class member.  */
    -     DB_TU_LOCAL_BIT,              /* It is a TU-local entity.  */
    +-    DB_TU_LOCAL_BIT,              /* It is a TU-local entity.  */
    ++    DB_TU_LOCAL_BIT,              /* Is a TU-local entity.  */
    ++    DB_REFS_TU_LOCAL_BIT, /* Refers to a TU-local entity (but is not
    ++                             necessarily an exposure.)  */
          DB_EXPOSURE_BIT,              /* Exposes a TU-local entity.  */
    -+    DB_IGNORED_EXPOSURE_BIT,      /* Will stream a TU-local entity.  */
          DB_IMPORTED_BIT,              /* An imported entity.  */
          DB_UNREACHED_BIT,             /* A yet-to-be reached entity.  */
    -     DB_HIDDEN_BIT,                /* A hidden binding.  */
     @@ gcc/cp/module.cc: public:
      public:
        bool has_defn () const
    @@ gcc/cp/module.cc: public:
      public:
     @@ gcc/cp/module.cc: public:
        {
    -     return get_flag_bit<DB_EXPOSURE_BIT> ();
    +     return get_flag_bit<DB_TU_LOCAL_BIT> ();
        }
    -+  bool is_ignored_exposure () const
    ++  bool refs_tu_local () const
     +  {
    -+    return get_flag_bit<DB_IGNORED_EXPOSURE_BIT> ();
    ++    return get_flag_bit<DB_REFS_TU_LOCAL_BIT> ();
     +  }
    -   bool is_import () const
    +   bool is_exposure () const
        {
    -     return get_flag_bit<DB_IMPORTED_BIT> ();
    +     return get_flag_bit<DB_EXPOSURE_BIT> ();
     @@ gcc/cp/module.cc: public:
          depset *current;         /* Current depset being depended.  */
          unsigned section;          /* When writing out, the section.  */
          bool reached_unreached;  /* We reached an unreached entity.  */
    -+    bool ignore_exposure;    /* In a context where exposures are ignored. 
 */
    ++    bool ignore_tu_local;    /* In a context where referencing a TU-local
    ++                          entity is not an exposure.  */
      
        public:
          hash (size_t size, hash *c = NULL)
            : parent (size), chain (c), current (NULL), section (0),
     -  reached_unreached (false)
    -+  reached_unreached (false), ignore_exposure (false)
    ++  reached_unreached (false), ignore_tu_local (false)
          {
            worklist.create (size);
          }
    @@ gcc/cp/module.cc: public:
      public:
        /* Serialize various definitions. */
     -  void write_definition (tree decl);
    -+  void write_definition (tree decl, bool has_tu_local = false);
    ++  void write_definition (tree decl, bool refs_tu_local = false);
        void mark_declaration (tree decl, bool do_defn);
      
      private:
    @@ gcc/cp/module.cc: trees_out::tree_node (tree t)
          goto done;
      
     +  /* Find TU-local entities and intercept streaming to instead write a
    -+     placeholder value; this way we don't need to expose such decls.
    ++     placeholder value; this way we don't need to emit such decls.
     +     We only need to do this when writing a definition of an entity
    -+     that we know is an ignored exposure.  */
    ++     that we know names a TU-local entity.  */
     +  if (!is_initial_scan () && writing_local_entities)
     +    {
     +      tree local_decl = NULL_TREE;
    @@ gcc/cp/module.cc: trees_in::tree_node (bool is_use)
      
     +    case tt_tu_local:
     +      {
    -+  /* A translation-unit local entity.  */
    ++  /* A translation-unit-local entity.  */
     +  res = make_node (TU_LOCAL_ENTITY);
     +  int tag = insert (res);
     +
    @@ gcc/cp/module.cc: void
     +       is ignored for determining exposures.  This should only matter
     +       for templates (we don't emit the bodies of non-inline functions
     +       to begin with).  */
    -+    auto ovr = make_temp_override (dep_hash->ignore_exposure,
    ++    auto ovr = make_temp_override (dep_hash->ignore_tu_local,
     +                             !DECL_DECLARED_INLINE_P (decl));
     +    tree_node (DECL_INITIAL (decl));
     +    tree_node (DECL_SAVED_TREE (decl));
    @@ gcc/cp/module.cc: trees_in::read_function_def (tree decl, tree 
maybe_template)
      {
     +  /* The initializer of a variable or variable template is ignored for
     +     determining exposures.  */
    -+  auto ovr = make_temp_override (dep_hash->ignore_exposure, VAR_P (decl));
    ++  auto ovr = make_temp_override (dep_hash->ignore_tu_local, VAR_P (decl));
     +
        tree init = DECL_INITIAL (decl);
        tree_node (init);
    @@ gcc/cp/module.cc: trees_out::write_class_def (tree defn)
     +      {
     +  /* Friend declarations in class definitions are ignored when
     +     determining exposures.  */
    -+  auto ovr = make_temp_override (dep_hash->ignore_exposure, true);
    ++  auto ovr = make_temp_override (dep_hash->ignore_tu_local, true);
      
     -      /* Write the friend functions.  */
     -      for (tree friends = DECL_FRIENDLIST (defn);
    @@ gcc/cp/module.cc: trees_in::read_enum_def (tree defn, tree 
maybe_template)
      
      void
     -trees_out::write_definition (tree decl)
    -+trees_out::write_definition (tree decl, bool has_tu_local)
    ++trees_out::write_definition (tree decl, bool refs_tu_local)
      {
     +  auto ovr = make_temp_override (writing_local_entities,
    -+                           writing_local_entities || has_tu_local);
    ++                           writing_local_entities || refs_tu_local);
     +
        if (streaming_p ())
          {
    @@ gcc/cp/module.cc: depset::hash::add_dependency (depset *dep)
        if (dep->is_tu_local ())
     -    current->set_flag_bit<DB_EXPOSURE_BIT> ();
     +    {
    -+      if (ignore_exposure)
    -+  current->set_flag_bit<DB_IGNORED_EXPOSURE_BIT> ();
    -+      else
    ++      current->set_flag_bit<DB_REFS_TU_LOCAL_BIT> ();
    ++      if (!ignore_tu_local)
     +  current->set_flag_bit<DB_EXPOSURE_BIT> ();
     +    }
      
    @@ gcc/cp/module.cc: depset::hash::find_dependencies (module_state *module)
                  walker.decl_value (decl, current);
                  if (current->has_defn ())
     -              walker.write_definition (decl);
    -+              walker.write_definition (decl,
    -+                                       current->is_ignored_exposure ());
    ++              walker.write_definition (decl, current->refs_tu_local ());
                }
              walker.end ();
      
    @@ gcc/cp/module.cc: depset::hash::finalize_dependencies ()
          /* We should have emitted an error above.  */
          gcc_checking_assert (explained);
        }
    -+      else if (warn_ignored_exposures && dep->is_ignored_exposure ())
    ++      else if (warn_template_names_tu_local
    ++         && dep->refs_tu_local () && !dep->is_tu_local ())
     +  {
     +    tree decl = dep->get_entity ();
     +
    @@ gcc/cp/module.cc: depset::hash::finalize_dependencies ()
     +    for (depset *rdep : dep->deps)
     +      if (!rdep->is_binding () && rdep->is_tu_local ())
     +        {
    -+          tree exposed = rdep->get_entity ();
    ++          tree ref = rdep->get_entity ();
     +          auto_diagnostic_group d;
     +          if (warning_at (DECL_SOURCE_LOCATION (decl),
    -+                          OPT_Wignored_exposures,
    ++                          OPT_Wtemplate_names_tu_local,
     +                          "%qD refers to TU-local entity %qD and cannot "
    -+                          "be instantiated in other TUs", decl, exposed))
    -+            is_tu_local_entity (exposed, /*explain=*/true);
    ++                          "be instantiated in other TUs", decl, ref))
    ++            is_tu_local_entity (ref, /*explain=*/true);
     +          break;
     +        }
     +  }
    @@ gcc/cp/module.cc: module_state::write_cluster (elf_out *to, depset 
*scc[], unsig
              sec.tree_node (decl);
              dump () && dump ("Writing definition %N", decl);
     -        sec.write_definition (decl);
    -+        sec.write_definition (decl, b->is_ignored_exposure ());
    ++        sec.write_definition (decl, b->refs_tu_local ());
      
              if (!namer->has_defn ())
                namer = b;
    @@ gcc/cp/pt.cc: tsubst_expr (tree t, tree args, tsubst_flags_t complain, 
tree in_d
     
      ## gcc/doc/invoke.texi ##
     @@ gcc/doc/invoke.texi: in the following sections.
    - -Weffc++ -Wno-elaborated-enum-base
    - -Wno-exceptions -Wextra-semi -Wno-global-module -Wno-inaccessible-base
    - -Wno-inherited-variadic-ctor  -Wno-init-list-lifetime
    ---Winvalid-constexpr -Winvalid-imported-macros
    -+-Wignored-exposures -Winvalid-constexpr -Winvalid-imported-macros
    - -Wno-invalid-offsetof  -Wno-literal-suffix
    - -Wmismatched-new-delete -Wmismatched-tags
    - -Wmultiple-inheritance  -Wnamespaces  -Wnarrowing
    -@@ gcc/doc/invoke.texi: the variable declaration statement.
    + -Woverloaded-virtual  -Wno-pmf-conversions -Wself-move -Wsign-promo
    + -Wsized-deallocation  -Wsuggest-final-methods
    + -Wsuggest-final-types  -Wsuggest-override  -Wno-template-body
    +--Wno-template-id-cdtor
    ++-Wno-template-id-cdtor  -Wtemplate-names-tu-local
    + -Wno-terminate  -Wno-vexing-parse  -Wvirtual-inheritance
    + -Wno-virtual-move-assign  -Wvolatile  -Wzero-as-null-pointer-constant}
      
    - @end itemize
    +@@ gcc/doc/invoke.texi: template<typename T> struct S @{
    + @option{-Wtemplate-id-cdtor} is enabled by default with
    + @option{-std=c++20}; it is also enabled by @option{-Wc++20-compat}.
      
    -+@opindex Wignored-exposures
    -+@opindex Wno-ignored-exposures
    -+@item -Wignored-exposures
    ++@opindex Wtemplate-names-tu-local
    ++@opindex Wno-template-names-tu-local
    ++@item -Wtemplate-names-tu-local
     +Warn when a template body hides an exposure of a translation-unit-local
     +entity.  In most cases, referring to a translation-unit-local entity
     +(such as an internal linkage declaration) within an entity that is
     +emitted into a module's CMI is an error.  However, within the
     +initializer of a variable, or in the body of a non-inline function,
    -+this error is suppressed.
    ++this is not an exposure and no error is emitted.
     +
     +This can cause variable or function templates to accidentally become
     +unusable if they reference such an entity, because other translation
     +units that import the template will never be able to instantiate it.
     +This warning attempts to detect cases where this might occur.
     +
    -+This warning is enabled by @option{-Wextra}.
    ++This flag is enabled by @option{-Wextra}.
     +
    - @opindex Winvalid-constexpr
    - @opindex Wno-invalid-constexpr
    - @item -Winvalid-constexpr
    + @opindex Wterminate
    + @opindex Wno-terminate
    + @item -Wno-terminate @r{(C++ and Objective-C++ only)}
     
      ## gcc/testsuite/g++.dg/modules/internal-5_a.C (new) ##
     @@
    -+// { dg-additional-options "-fmodules-ts -Wignored-exposures" }
    ++// { dg-additional-options "-fmodules-ts -Wtemplate-names-tu-local" }
     +// { dg-module-cmi M }
     +// Ignore exposures in these cases
     +
    @@ gcc/testsuite/g++.dg/modules/internal-5_a.C (new)
     +  internal_tmpl<T>();
     +}
     +template void function_tmpl<ok_inst_tag>();
    ++template <> void function_tmpl<ok_inst_tag*>() {}
     +
     +
     +// The initializer for a variable or variable template
    @@ gcc/testsuite/g++.dg/modules/internal-5_a.C (new)
     +     internal_ovl(internal_x), internal_tmpl<T*>(), 0);
     +
     +template int var_tmpl<ok_inst_tag>;
    -+template int var_tmpl<ok_inst_tag*>;
    ++template <> int var_tmpl<ok_inst_tag*> = 0;
     +
     +export int& constant_ref = internal_x;
     +static_assert (&constant_ref == &internal_x);
    @@ gcc/testsuite/g++.dg/modules/internal-5_a.C (new)
     +// Any reference to a non-volatile const object or reference with 
internal or
     +// no linkage initialized with a constant expression that is not an 
ODR-use
     +static const int value = 123;
    -+static const int& ref = value;
    ++static const int& ref = 456;
     +static const internal_t internal {};
    ++void f(int) {}
     +export inline void no_odr_use() {
     +  int x = value;
     +  int y = ref;
     +  int z = (internal, 0);
    ++
    ++  value;
    ++  bool b = value < value;
    ++  f(value);
     +}
     
      ## gcc/testsuite/g++.dg/modules/internal-5_b.C (new) ##
    @@ gcc/testsuite/g++.dg/modules/internal-5_b.C (new)
     +  no_odr_use();
     +
     +  function_tmpl<ok_inst_tag>();
    ++  function_tmpl<ok_inst_tag*>();
     +  int b = var_tmpl<ok_inst_tag>;
     +  int c = var_tmpl<ok_inst_tag*>;
     +
    @@ gcc/testsuite/g++.dg/modules/internal-6.C (new)
     
      ## gcc/testsuite/g++.dg/modules/internal-7_a.C (new) ##
     @@
    -+// { dg-additional-options "-fmodules-ts -Wignored-exposures" }
    ++// { dg-additional-options "-fmodules-ts -Wtemplate-names-tu-local" }
     +// Test streaming and instantiations of various kinds of exposures
     +
     +export module M;
    @@ gcc/testsuite/g++.dg/modules/internal-7_b.C (new)
     +}
     +
     +// { dg-error "instantiation exposes TU-local entity" "" { target *-*-* } 
0 }
    +
    + ## gcc/testsuite/g++.dg/modules/internal-8_a.C (new) ##
    +@@
    ++// { dg-additional-options "-fmodules-ts -Wtemplate-names-tu-local" }
    ++// Non-ODR usages of const variables currently are erroneously
    ++// reported in templates and constexpr functions; this test
    ++// XFAILS them until we can implement a fix.
    ++
    ++export module M;
    ++
    ++namespace { struct internal_t {}; };
    ++static const int value = 123;
    ++static const int& ref = 456;
    ++static const internal_t internal {};
    ++
    ++constexpr void f(int) {}
    ++
    ++export constexpr
    ++void no_odr_use_cexpr() {  // { dg-bogus "TU-local" "" { xfail *-*-* } }
    ++  int x = value;
    ++  int y = ref;
    ++  int z = (internal, 0);
    ++
    ++  value;
    ++  bool b = value < value;
    ++  f(value);
    ++}
    ++
    ++export template <typename T>
    ++void no_odr_use_templ() {  // { dg-bogus "TU-local" "" { xfail *-*-* } }
    ++  int x = value;
    ++  int y = ref;
    ++  int z = (internal, 0);
    ++
    ++  value;
    ++  bool b = value < value;
    ++  f(value);
    ++}
    +
    + ## gcc/testsuite/g++.dg/modules/xtreme-header-8.C (new) ##
    +@@
    ++// PR c++/115126
    ++// { dg-additional-options "-fmodules-ts -Wtemplate-names-tu-local" }
    ++// { dg-module-cmi xstd }
    ++
    ++export module xstd;
    ++extern "C++" {
    ++  #include "xtreme-header.h"
    ++}
3:  49e06cc4065 ! 3:  918c037a0a9 c++/modules: Support anonymous namespaces in 
header units
    @@ Metadata
     Author: Nathaniel Shead <nathanielosh...@gmail.com>
     
      ## Commit message ##
    -    c++/modules: Support anonymous namespaces in header units
    +    c++/modules: Support unnamed namespaces in header units
     
    -    A header unit may contain anonymous namespaces, and those declarations
    +    A header unit may contain unnamed namespaces, and those declarations
         are exported (as with any declaration in a header unit).  This patch
         ensures that such declarations are correctly handled.
     
    -    The change to 'make_namespace_finish' is required so that if an
    -    anonymous namespace is first seen by an import it is correctly handled
    -    within 'add_imported_namespace'.  I don't see any particular reason why
    -    handling of anonymous namespaces here had to be handled separately
    -    outside that function since these are the only two callers.
    +    The change to 'make_namespace_finish' is required so that if an unnamed
    +    namespace is first seen by an import it is correctly handled within
    +    'add_imported_namespace'.  I don't see any particular reason why
    +    handling of unnamed namespaces here had to be handled separately 
outside
    +    that function since these are the only two callers.
     
         gcc/cp/ChangeLog:
     
                 * module.cc (depset::hash::add_binding_entity): Also walk
    -            anonymous namespaces.
    +            unnamed namespaces.
                 (module_state::write_namespaces): Adjust assertion.
                 * name-lookup.cc (push_namespace): Move anon using-directive
                 handling to...
    @@ Commit message
     
         gcc/testsuite/ChangeLog:
     
    -            * g++.dg/modules/internal-8_a.H: New test.
    -            * g++.dg/modules/internal-8_b.C: New test.
    +            * g++.dg/modules/internal-9_a.H: New test.
    +            * g++.dg/modules/internal-9_b.C: New test.
     
         Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
    +    Reviewed-by: Jason Merrill <ja...@redhat.com>
     
      ## gcc/cp/module.cc ##
     @@ gcc/cp/module.cc: depset::hash::add_binding_entity (tree decl, 
WMB_Flags flags, void *data_)
    @@ gcc/cp/name-lookup.cc: make_namespace_finish (tree ns, tree *slot, bool 
from_imp
        if (DECL_NAMESPACE_INLINE_P (ns) || !DECL_NAME (ns))
          emit_debug_info_using_namespace (ctx, ns, true);
     +
    ++  /* An unnamed namespace implicitly has a using-directive inserted so
    ++     that its contents are usable in the surrounding context.  */
     +  if (!DECL_NAMESPACE_INLINE_P (ns) && !DECL_NAME (ns))
     +    add_using_namespace (NAMESPACE_LEVEL (ctx)->using_directives, ns);
      }
    @@ gcc/cp/name-lookup.cc: push_namespace (tree name, bool make_inline)
          }
      
     
    - ## gcc/testsuite/g++.dg/modules/internal-8_a.H (new) ##
    + ## gcc/testsuite/g++.dg/modules/internal-9_a.H (new) ##
     @@
     +// { dg-additional-options "-fmodule-header" }
     +// { dg-module-cmi {} }
    @@ gcc/testsuite/g++.dg/modules/internal-8_a.H (new)
     +
     +namespace ns2 = ns;
     
    - ## gcc/testsuite/g++.dg/modules/internal-8_b.C (new) ##
    + ## gcc/testsuite/g++.dg/modules/internal-9_b.C (new) ##
     @@
     +// { dg-additional-options "-fmodules-ts" }
     +
    -+import "internal-8_a.H";
    ++import "internal-9_a.H";
     +
     +int main() {
     +  auto x2 = x;
4:  671a9de084e ! 4:  46d0ecf964c c++/modules: Check linkage for exported 
declarations
    @@ Commit message
                 * g++.dg/modules/export-6.C: New test.
     
         Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
    +    Reviewed-by: Jason Merrill <ja...@redhat.com>
     
      ## gcc/cp/cp-tree.h ##
     @@ gcc/cp/cp-tree.h: extern void set_originating_module (tree, bool 
friend_p = false);
    @@ gcc/cp/module.cc: set_originating_module (tree decl, bool friend_p 
ATTRIBUTE_UNU
          }
      
     -  if (!module_exporting_p ())
    -+  /* It is illegal to export a declaration with internal linkage.  
However, at
    -+     the point this function is called we don't always know yet whether 
this
    ++  /* It is ill-formed to export a declaration with internal linkage.  
However,
    ++     at the point this function is called we don't yet always know 
whether this
     +     declaration has internal linkage; instead we defer this check for 
callers
     +     to do once visibility has been determined.  */
     +  if (module_exporting_p ())
    @@ gcc/cp/name-lookup.cc: push_namespace (tree name, bool make_inline)
     -                "exporting namespace with internal linkage");
     +      {
     +        if (name)
    -+          error_at (input_location,
    -+                    "exporting namespace %qD with internal linkage", ns);
    ++          {
    ++            auto_diagnostic_group d;
    ++            error_at (input_location, "exporting namespace %qD with "
    ++                      "internal linkage", ns);
    ++            inform (input_location, "%qD has internal linkage because "
    ++                    "it was declared in an unnamed namespace", ns);
    ++          }
     +        else
    -+          error_at (input_location, "exporting anonymous namespace");
    ++          error_at (input_location, "exporting unnamed namespace");
     +      }
        }
            if (module_purview_p ())
    @@ gcc/testsuite/g++.dg/modules/export-3.C: namespace {
      }
      
     -export namespace {}  // { dg-error "internal linkage" }
    -+export namespace {}  // { dg-error "exporting anonymous namespace" }
    ++export namespace {}  // { dg-error "exporting unnamed namespace" }
     
      ## gcc/testsuite/g++.dg/modules/export-6.C (new) ##
     @@
    @@ gcc/testsuite/g++.dg/modules/export-6.C (new)
     +#endif
     +}
     +
    -+export namespace {}  // { dg-error "exporting anonymous namespace" }
    ++export namespace {}  // { dg-error "exporting unnamed namespace" }
     +export namespace ns2 = ns;  // { dg-error "internal linkage" }
     
      ## libcc1/libcp1plugin.cc ##
5:  0923d54daf1 ! 5:  3470fe5b429 c++/modules: Validate external linkage 
definitions in header units [PR116401]
    @@ Commit message
                 * g++.dg/modules/hdr-2.H: New test.
     
         Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
    +    Reviewed-by: Jason Merrill <ja...@redhat.com>
     
      ## gcc/cp/decl.cc ##
     @@ gcc/cp/decl.cc: grokfndecl (tree ctype,
         have one: the restriction that you can't repeat a deduction guide
         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.  */
     +      DECL_DECLARED_INLINE_P (decl) = true;
            break;
          default:
6:  0f78398918f < -:  ----------- c++/modules: Add testcase for 
standard-library exposures [PR115126]
-- 
2.46.0

Reply via email to