c++: Decl module-specific semantic processing
authorNathan Sidwell <nathan@acm.org>
Wed, 9 Dec 2020 12:52:51 +0000 (04:52 -0800)
committerNathan Sidwell <nathan@acm.org>
Wed, 9 Dec 2020 12:56:47 +0000 (04:56 -0800)
This adds the module-specific logic to the various declaration
processing routines in decl.c and semantic.c.  I also adjust the rtti
type creation, as those are all in the global module, so we need to
temporarily clear the module_kind, when they are being created.
Finally, I added init and fini module processing with the initialier
giving a fatal error if you try and turn it on (so don't do that yet).

gcc/cp/
* decl.c (duplicate_decls): Add module-specific redeclaration
logic.
(cxx_init_decl_processing): Export the global namespace, maybe
initialize modules.
(start_decl): Reject local-extern in a module, adjust linkage of
template var.
(xref_tag_1): Add module-specific redeclaration logic.
(start_enum): Likewise.
(finish_enum_value_list): Export unscoped members of an exported
enum.
(grokmethod): Implement p1779 linkage of in-class defined
functions.
* decl2.c (no_linkage_error): Imports are ok.
(c_parse_final_cleanups): Call fini_modules.
* lex.c (cxx_dup_lang_specific): Clear some module flags in the
copy.
* module.cc (module_kind): Define.
(module_may_redeclare, set_defining_module): Stubs.
(init_modules): Error on modules.
(fini_modules): Stub.
* rtti.c (push_abi_namespace): Save and reset module_kind.
(pop_abi_namespace): Restore module kind.
(build_dynamic_cast_1, tinfo_base_init): Adjust.
* semantics.c (begin_class_definition): Add module-specific logic.
(expand_or_defer_fn_1): Keep bodies of more fns when modules_p.

gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/lex.c
gcc/cp/module.cc
gcc/cp/rtti.c
gcc/cp/semantics.c

index bb5bb2f1a18cf148df85c734920b52aed6652d47..ae93fe1d7f0747c92da0559d630a66ce3f3d837a 100644 (file)
@@ -2008,6 +2008,39 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
   if (!validate_constexpr_redeclaration (olddecl, newdecl))
     return error_mark_node;
 
+  if (modules_p ()
+      && TREE_CODE (CP_DECL_CONTEXT (olddecl)) == NAMESPACE_DECL
+      && TREE_CODE (olddecl) != NAMESPACE_DECL
+      && !hiding)
+    {
+      if (DECL_ARTIFICIAL (olddecl))
+       {
+         gcc_checking_assert (!(DECL_LANG_SPECIFIC (olddecl)
+                                && DECL_MODULE_IMPORT_P (olddecl)));
+         if (!(global_purview_p () || not_module_p ()))
+           error ("declaration %qD conflicts with builtin", newdecl);
+         else
+           DECL_MODULE_EXPORT_P (olddecl) = DECL_MODULE_EXPORT_P (newdecl);
+       }
+      else
+       {
+         if (!module_may_redeclare (olddecl))
+           {
+             error ("declaration %qD conflicts with import", newdecl);
+             inform (olddecl_loc, "import declared %q#D here", olddecl);
+
+             return error_mark_node;
+           }
+
+         if (DECL_MODULE_EXPORT_P (newdecl)
+             && !DECL_MODULE_EXPORT_P (olddecl))
+           {
+             error ("conflicting exporting declaration %qD", newdecl);
+             inform (olddecl_loc, "previous declaration %q#D here", olddecl);
+           }
+       }
+    }
+
   /* We have committed to returning OLDDECL at this point.  */
 
   /* If new decl is `static' and an `extern' was seen previously,
@@ -2218,6 +2251,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
            }
        }
 
+      DECL_MODULE_IMPORT_P (olddecl)
+       = DECL_MODULE_IMPORT_P (old_result)
+       = DECL_MODULE_IMPORT_P (newdecl);
+
       return olddecl;
     }
 
@@ -2836,6 +2873,20 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
       memcpy ((char *) olddecl + sizeof (struct tree_common),
              (char *) newdecl + sizeof (struct tree_common),
              sizeof (struct tree_decl_common) - sizeof (struct tree_common));
+
+      if (DECL_LANG_SPECIFIC (olddecl) && DECL_TEMPLATE_INFO (olddecl))
+       {
+         /* Repropagate the module information to the template.  */
+         tree tmpl = DECL_TI_TEMPLATE (olddecl);
+
+         if (DECL_TEMPLATE_RESULT (tmpl) == olddecl)
+           {
+             DECL_MODULE_PURVIEW_P (tmpl) = DECL_MODULE_PURVIEW_P (olddecl);
+             gcc_checking_assert (!DECL_MODULE_IMPORT_P (olddecl));
+             DECL_MODULE_IMPORT_P (tmpl) = false;
+           }
+       }
+
       switch (TREE_CODE (newdecl))
        {
        case LABEL_DECL:
@@ -4330,7 +4381,8 @@ cxx_init_decl_processing (void)
   gcc_assert (global_namespace == NULL_TREE);
   global_namespace = build_lang_decl (NAMESPACE_DECL, global_identifier,
                                      void_type_node);
-  TREE_PUBLIC (global_namespace) = 1;
+  TREE_PUBLIC (global_namespace) = true;
+  DECL_MODULE_EXPORT_P (global_namespace) = true;
   DECL_CONTEXT (global_namespace)
     = build_translation_unit_decl (get_identifier (main_input_filename));
   /* Remember whether we want the empty class passing ABI change warning
@@ -4629,6 +4681,9 @@ cxx_init_decl_processing (void)
   if (! supports_one_only ())
     flag_weak = 0;
 
+  if (modules_p ())
+    init_modules (parse_in);
+
   make_fname_decl = cp_make_fname_decl;
   start_fname_decls ();
 
@@ -5453,8 +5508,14 @@ start_decl (const cp_declarator *declarator,
 
   if ((DECL_EXTERNAL (decl) || TREE_CODE (decl) == FUNCTION_DECL)
       && current_function_decl)
-    /* A function-scope decl of some namespace-scope decl.  */
-    DECL_LOCAL_DECL_P (decl) = true;
+    {
+      /* A function-scope decl of some namespace-scope decl.  */
+      DECL_LOCAL_DECL_P (decl) = true;
+      if (named_module_purview_p ())
+       error_at (declarator->id_loc,
+                 "block-scope extern declaration %q#D not permitted"
+                 " in module purview", decl);
+    }
 
   /* Enter this declaration into the symbol table.  Don't push the plain
      VAR_DECL for a variable template.  */
@@ -5470,7 +5531,9 @@ start_decl (const cp_declarator *declarator,
 
   if (VAR_P (decl)
       && DECL_NAMESPACE_SCOPE_P (decl) && !TREE_PUBLIC (decl) && !was_public
-      && !DECL_THIS_STATIC (decl) && !DECL_ARTIFICIAL (decl))
+      && !DECL_THIS_STATIC (decl) && !DECL_ARTIFICIAL (decl)
+      /* But not templated variables.  */
+      && !(DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)))
     {
       /* This is a const variable with implicit 'static'.  Set
         DECL_THIS_STATIC so we can tell it from variables that are
@@ -15143,6 +15206,41 @@ xref_tag_1 (enum tag_types tag_code, tree name,
          inform (location_of (t), "previous declaration %qD", t);
          return error_mark_node;
        }
+
+      if (modules_p ()
+         && how == TAG_how::CURRENT_ONLY)
+       {
+         tree decl = TYPE_NAME (t);
+         if (!module_may_redeclare (decl))
+           {
+             error ("cannot declare %qD in a different module", decl);
+             inform (DECL_SOURCE_LOCATION (decl), "declared here");
+             return error_mark_node;
+           }
+
+         tree maybe_tmpl = decl;
+         if (CLASS_TYPE_P (t) && CLASSTYPE_IS_TEMPLATE (t))
+           maybe_tmpl = CLASSTYPE_TI_TEMPLATE (t);
+
+         if (DECL_LANG_SPECIFIC (decl)
+             && DECL_MODULE_IMPORT_P (decl)
+             && TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL)
+           {
+             /* Push it into this TU's symbol slot.  */
+             gcc_checking_assert (current_namespace == CP_DECL_CONTEXT (decl));
+             if (maybe_tmpl != decl)
+               /* We're in the template parm binding level.
+                  Pushtag has logic to slide under that, but we're
+                  not pushing a *new* type.  */
+               push_nested_namespace (CP_DECL_CONTEXT (decl));
+
+             pushdecl (maybe_tmpl);
+             if (maybe_tmpl != decl)
+               pop_nested_namespace (CP_DECL_CONTEXT (decl));
+           }
+
+         set_instantiating_module (maybe_tmpl);
+       }
     }
 
   return t;
@@ -15487,6 +15585,19 @@ start_enum (tree name, tree enumtype, tree underlying_type,
                  "previous definition here");
          underlying_type = NULL_TREE;
        }
+
+      if (modules_p ())
+       {
+         if (!module_may_redeclare (TYPE_NAME (enumtype)))
+           {
+             error ("cannot define %qD in different module",
+                    TYPE_NAME (enumtype));
+             inform (DECL_SOURCE_LOCATION (TYPE_NAME (enumtype)),
+                     "declared here");
+             enumtype = error_mark_node;
+           }
+         set_instantiating_module (TYPE_NAME (enumtype));
+       }
     }
 
   if (!enumtype || TREE_CODE (enumtype) != ENUMERAL_TYPE
@@ -15747,6 +15858,11 @@ finish_enum_value_list (tree enumtype)
   else
     underlying_type = ENUM_UNDERLYING_TYPE (enumtype);
 
+  /* If the enum is exported, mark the consts too.  */
+  bool export_p = (UNSCOPED_ENUM_P (enumtype)
+                  && DECL_MODULE_EXPORT_P (TYPE_STUB_DECL (enumtype))
+                  && at_namespace_scope_p ());
+
   /* Convert each of the enumerators to the type of the underlying
      type of the enumeration.  */
   for (values = TYPE_VALUES (enumtype); values; values = TREE_CHAIN (values))
@@ -15769,6 +15885,8 @@ finish_enum_value_list (tree enumtype)
          TREE_TYPE (value) = enumtype;
        }
       DECL_INITIAL (decl) = value;
+      if (export_p)
+       DECL_MODULE_EXPORT_P (decl) = true;
     }
 
   /* Fix up all variant types of this enum type.  */
@@ -17366,10 +17484,25 @@ grokmethod (cp_decl_specifier_seq *declspecs,
 
   check_template_shadow (fndecl);
 
-  if (TREE_PUBLIC (fndecl))
-    DECL_COMDAT (fndecl) = 1;
-  DECL_DECLARED_INLINE_P (fndecl) = 1;
-  DECL_NO_INLINE_WARNING_P (fndecl) = 1;
+  /* p1779 ABI-Isolation makes inline not a default for in-class
+     definitions in named module purview.  If the user explicitly
+     made it inline, grokdeclarator will already have done the right
+     things.  */
+  if ((!named_module_purview_p ()
+       || flag_module_implicit_inline
+      /* Lambda's operator function remains inline.  */
+       || LAMBDA_TYPE_P (DECL_CONTEXT (fndecl)))
+      /* If the user explicitly asked for this to be inline, we don't
+        need to do more, but more importantly we want to warn if we
+        can't inline it.  */
+      && !DECL_DECLARED_INLINE_P (fndecl))
+    {
+      if (TREE_PUBLIC (fndecl))
+       DECL_COMDAT (fndecl) = 1;
+      DECL_DECLARED_INLINE_P (fndecl) = 1;
+      /* It's ok if we can't inline this.  */
+      DECL_NO_INLINE_WARNING_P (fndecl) = 1;
+    }
 
   /* We process method specializations in finish_struct_1.  */
   if (processing_template_decl && !DECL_TEMPLATE_SPECIALIZATION (fndecl))
index eec0c9255c29ece074b16c68c68807082fd6a1ff..c122017c2faee8317c900762a13c20cdb6c0902d 100644 (file)
@@ -4531,6 +4531,10 @@ no_linkage_error (tree decl)
     /* In C++11 it's ok if the decl is defined.  */
     return;
 
+  if (DECL_LANG_SPECIFIC (decl) && DECL_MODULE_IMPORT_P (decl))
+    /* An imported decl is ok.  */
+    return;
+
   tree t = no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false);
   if (t == NULL_TREE)
     /* The type that got us on no_linkage_decls must have gotten a name for
@@ -5226,6 +5230,8 @@ c_parse_final_cleanups (void)
   if (priority_info_map)
     splay_tree_delete (priority_info_map);
 
+  fini_modules ();
+
   /* Generate any missing aliases.  */
   maybe_apply_pending_pragma_weaks ();
 
index 6053848535e7a97d2511e17412a6b0b9562eaf8c..339ed479a9a37a1cf4989823f7fc7862d0aae81d 100644 (file)
@@ -1006,6 +1006,12 @@ cxx_dup_lang_specific_decl (tree node)
   memcpy (ld, DECL_LANG_SPECIFIC (node), size);
   DECL_LANG_SPECIFIC (node) = ld;
 
+  /* Directly clear some flags that do not apply to the copy
+     (module_purview_p still does).  */
+  ld->u.base.module_entity_p = false;
+  ld->u.base.module_import_p = false;
+  ld->u.base.module_pending_p = false;
+  
   if (GATHER_STATISTICS)
     {
       tree_node_counts[(int)lang_decl] += 1;
index 948ca2a6cabbe8fc21573b42622b3e18b95b588e..a961e3bcc92ad6aad835887d1cbb8e4299d5cea1 100644 (file)
@@ -65,6 +65,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "intl.h"
 #include "langhooks.h"
 
+/* What the current TU is.  */
+unsigned module_kind;
+
 module_state *
 get_module (tree, module_state *, bool)
 {
@@ -99,11 +102,22 @@ get_originating_module (tree, bool)
   return 0;
 }
 
+bool
+module_may_redeclare (tree)
+{
+  return true;
+}
+
 void
 set_instantiating_module (tree)
 {
 }
 
+void
+set_defining_module (tree)
+{
+}
+
 void
 set_originating_module (tree, bool)
 {
@@ -120,3 +134,16 @@ preprocessed_module (cpp_reader *)
 {
 }
 
+void
+init_modules (cpp_reader *)
+{
+  /* Do not turn on yet.  */
+  if (modules_p ())
+    fatal_error (input_location,
+                "Shtopp! What are you doing? This is not ready yet.");
+}
+
+void
+fini_modules ()
+{
+}
index d6288622246d68e60351ca4272c7d1af5b485db5..0be9eff54adbe57e16f038e5704e477943ca11c9 100644 (file)
@@ -143,16 +143,20 @@ static bool typeinfo_in_lib_p (tree);
 
 static int doing_runtime = 0;
 \f
-static void
+static unsigned
 push_abi_namespace (void)
 {
   push_nested_namespace (abi_node);
   push_visibility ("default", 2);
+  unsigned flags = module_kind;
+  module_kind = 0;
+  return flags;
 }
 
 static void
-pop_abi_namespace (void)
+pop_abi_namespace (unsigned flags)
 {
+  module_kind = flags;
   pop_visibility (2);
   pop_nested_namespace (abi_node);
 }
@@ -765,7 +769,7 @@ build_dynamic_cast_1 (location_t loc, tree type, tree expr,
          dcast_fn = dynamic_cast_node;
          if (!dcast_fn)
            {
-             push_abi_namespace ();
+             unsigned flags = push_abi_namespace ();
              tree tinfo_ptr = xref_tag (class_type,
                                         get_identifier ("__class_type_info"));
              tinfo_ptr = cp_build_qualified_type (tinfo_ptr, TYPE_QUAL_CONST);
@@ -780,7 +784,7 @@ build_dynamic_cast_1 (location_t loc, tree type, tree expr,
                               NULL_TREE));
              dcast_fn = (build_library_fn_ptr
                          (fn_name, fn_type, ECF_LEAF | ECF_PURE | ECF_NOTHROW));
-             pop_abi_namespace ();
+             pop_abi_namespace (flags);
              dynamic_cast_node = dcast_fn;
            }
          result = build_cxx_call (dcast_fn, 4, elems, complain);
@@ -954,11 +958,11 @@ tinfo_base_init (tinfo_s *ti, tree target)
   vtable_ptr = ti->vtable;
   if (!vtable_ptr)
     {
-      push_abi_namespace ();
+      int flags = push_abi_namespace ();
       tree real_type = xref_tag (class_type, ti->name);
       tree real_decl = TYPE_NAME (real_type);
       DECL_SOURCE_LOCATION (real_decl) = BUILTINS_LOCATION;
-      pop_abi_namespace ();
+      pop_abi_namespace (flags);
 
       if (!COMPLETE_TYPE_P (real_type))
        {
index d33ef4263486975b0047b7dff2aec1b15c57c966..92e32c8e0ad8601e91a41cd3dbcdb187d32814be 100644 (file)
@@ -3220,6 +3220,19 @@ begin_class_definition (tree t)
       t = make_class_type (TREE_CODE (t));
       pushtag (TYPE_IDENTIFIER (t), t);
     }
+
+  if (modules_p ())
+    {
+      if (!module_may_redeclare (TYPE_NAME (t)))
+       {
+         error ("cannot declare %qD in a different module", TYPE_NAME (t));
+         inform (DECL_SOURCE_LOCATION (TYPE_NAME (t)), "declared here");
+         return error_mark_node;
+       }
+      set_instantiating_module (TYPE_NAME (t));
+      set_defining_module (TYPE_NAME (t));
+    }
+
   maybe_process_partial_specialization (t);
   pushclass (t);
   TYPE_BEING_DEFINED (t) = 1;
@@ -4506,7 +4519,8 @@ expand_or_defer_fn_1 (tree fn)
         it out, even though we haven't.  */
       TREE_ASM_WRITTEN (fn) = 1;
       /* If this is a constexpr function, keep DECL_SAVED_TREE.  */
-      if (!DECL_DECLARED_CONSTEXPR_P (fn))
+      if (!DECL_DECLARED_CONSTEXPR_P (fn)
+         && !(modules_p () && DECL_DECLARED_INLINE_P (fn)))
        DECL_SAVED_TREE (fn) = NULL_TREE;
       return false;
     }