]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++/modules: Give more specific diagnostics in is_matching_decl
authorNathaniel Shead <nathanieloshead@gmail.com>
Thu, 10 Apr 2025 21:09:33 +0000 (07:09 +1000)
committerNathaniel Shead <nathanieloshead@gmail.com>
Sun, 13 Apr 2025 10:33:37 +0000 (20:33 +1000)
This patch also rephrases the diagnostics to talk about "imported
declarations" rather than "global module declarations", since as the
FIXME noted we can also get mismatches with some declarations attached
to modules.  Ideally I'd like to revisit the way this is structured
entirely but that won't be appropriate for GCC 15.

gcc/cp/ChangeLog:

* module.cc (trees_in::is_matching_decl): Add custom errors for
different kinds of mismatches.

gcc/testsuite/ChangeLog:

* g++.dg/modules/lambda-8_b.C: Adjust error.
* g++.dg/modules/leg-merge-4_c.C: Likewise.

Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
gcc/cp/module.cc
gcc/testsuite/g++.dg/modules/lambda-8_b.C
gcc/testsuite/g++.dg/modules/leg-merge-4_c.C

index 37fab5b5a43e3c3ea1c9fbf4ca4b792bf4fc2274..8efa18baff1de4997c776b200c508c27e5e0aca1 100644 (file)
@@ -12090,6 +12090,8 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
       gcc_checking_assert (TREE_CODE (e_inner) == TREE_CODE (d_inner));
     }
 
+  // FIXME: do more precise errors at point of mismatch
+  const char *mismatch_msg = nullptr;
   if (TREE_CODE (d_inner) == FUNCTION_DECL)
     {
       tree e_ret = fndecl_declared_return_type (existing);
@@ -12099,13 +12101,20 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
          && LAMBDA_TYPE_P (DECL_CONTEXT (d_inner)))
        /* This has a recursive type that will compare different.  */;
       else if (!same_type_p (d_ret, e_ret))
-       goto mismatch;
+       {
+         mismatch_msg = G_("conflicting type for imported declaration %#qD");
+         goto mismatch;
+       }
 
       tree e_type = TREE_TYPE (e_inner);
       tree d_type = TREE_TYPE (d_inner);
 
       if (DECL_EXTERN_C_P (d_inner) != DECL_EXTERN_C_P (e_inner))
-       goto mismatch;
+       {
+         mismatch_msg = G_("conflicting language linkage for imported "
+                           "declaration %#qD");
+         goto mismatch;
+       }
 
       for (tree e_args = TYPE_ARG_TYPES (e_type),
             d_args = TYPE_ARG_TYPES (d_type);
@@ -12113,10 +12122,18 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
           e_args = TREE_CHAIN (e_args), d_args = TREE_CHAIN (d_args))
        {
          if (!(e_args && d_args))
-           goto mismatch;
+           {
+             mismatch_msg = G_("conflicting argument list for imported "
+                               "declaration %#qD");
+             goto mismatch;
+           }
 
          if (!same_type_p (TREE_VALUE (d_args), TREE_VALUE (e_args)))
-           goto mismatch;
+           {
+             mismatch_msg = G_("conflicting argument types for imported "
+                               "declaration %#qD");
+             goto mismatch;
+           }
        }
 
       /* If EXISTING has an undeduced or uninstantiated exception
@@ -12149,7 +12166,11 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
        }
       else if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec)
               && !comp_except_specs (d_spec, e_spec, ce_type))
-       goto mismatch;
+       {
+         mismatch_msg = G_("conflicting %<noexcept%> specifier for "
+                           "imported declaration %#qD");
+         goto mismatch;
+       }
 
       /* Similarly if EXISTING has an undeduced return type, but DECL's
         is already deduced.  */
@@ -12163,7 +12184,11 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
        }
       else if (type_uses_auto (d_ret)
               && !same_type_p (TREE_TYPE (d_type), TREE_TYPE (e_type)))
-       goto mismatch;
+       {
+         mismatch_msg = G_("conflicting deduced return type for "
+                           "imported declaration %#qD");
+         goto mismatch;
+       }
 
       /* Similarly if EXISTING has undeduced constexpr, but DECL's
         is already deduced.  */
@@ -12172,7 +12197,11 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
        DECL_DECLARED_CONSTEXPR_P (e_inner) = true;
       else if (DECL_DECLARED_CONSTEXPR_P (e_inner)
               != DECL_DECLARED_CONSTEXPR_P (d_inner))
-       goto mismatch;
+       {
+         mismatch_msg = G_("conflicting %<constexpr%> for imported "
+                           "declaration %#qD");
+         goto mismatch;
+       }
 
       /* Don't synthesize a defaulted function if we're importing one
         we've already determined.  */
@@ -12184,13 +12213,17 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
       if (!DECL_ORIGINAL_TYPE (e_inner)
          || !same_type_p (DECL_ORIGINAL_TYPE (d_inner),
                           DECL_ORIGINAL_TYPE (e_inner)))
-       goto mismatch;
+       {
+         mismatch_msg = G_("conflicting imported declaration %q#D");
+         goto mismatch;
+       }
     }
   /* Using cp_tree_equal because we can meet TYPE_ARGUMENT_PACKs
      here. I suspect the entities that directly do that are things
      that shouldn't go to duplicate_decls (FIELD_DECLs etc).   */
   else if (!cp_tree_equal (TREE_TYPE (decl), TREE_TYPE (existing)))
     {
+      mismatch_msg = G_("conflicting type for imported declaration %#qD");
     mismatch:
       if (DECL_IS_UNDECLARED_BUILTIN (existing))
        /* Just like duplicate_decls, presum the user knows what
@@ -12203,11 +12236,9 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
           equality isn't feasible in general for local entities.  */;
       else
        {
-         // FIXME:QOI Might be template specialization from a module,
-         // not necessarily global module
+         gcc_checking_assert (mismatch_msg);
          auto_diagnostic_group d;
-         error_at (DECL_SOURCE_LOCATION (decl),
-                   "conflicting global module declaration %#qD", decl);
+         error_at (DECL_SOURCE_LOCATION (decl), mismatch_msg, decl);
          inform (DECL_SOURCE_LOCATION (existing),
                  "existing declaration %#qD", existing);
          return false;
index 7ace4944dd2d0a8e3cd2f0986f37baa723735613..96578ba94cbe6821a38f9880678c1c2c9fc13322 100644 (file)
@@ -4,4 +4,4 @@
 #include "lambda-8.h"
 import "lambda-8_a.H";
 
-// { dg-error "conflicting global module declaration" "" { target *-*-* } 0 }
+// { dg-error "conflicting imported declaration" "" { target *-*-* } 0 }
index f1b1aeb5b37f77cd326494bc9ca51a0eb089d3ce..5756057ce0bb918b85831099e37a5a3ab8cd8957 100644 (file)
@@ -11,8 +11,8 @@ void foo ()
   X *p;
 }
 
-// { dg-regexp "\nIn module \[^\n]*leg-merge-4_b.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_b.H:4:\[0-9]*: error: conflicting global module declaration 'float bob'\nIn module \[^\n]*leg-merge-4_a.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_a.H:4:\[0-9]*: note: existing declaration 'int bob'\n\[^\n]*leg-merge-4_c.C:9:\[0-9]*: note: during load of binding '::bob'$" }
+// { dg-regexp "\nIn module \[^\n]*leg-merge-4_b.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_b.H:4:\[0-9]*: error: conflicting type for imported declaration 'float bob'\nIn module \[^\n]*leg-merge-4_a.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_a.H:4:\[0-9]*: note: existing declaration 'int bob'\n\[^\n]*leg-merge-4_c.C:9:\[0-9]*: note: during load of binding '::bob'$" }
 
-// { dg-regexp "\nIn module \[^\n]*leg-merge-4_b.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_b.H:5:\[0-9]*: error: conflicting global module declaration 'int frob\\(\\)'\nIn module \[^\n]*leg-merge-4_a.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_a.H:5:\[0-9]*: note: existing declaration 'void frob\\(\\)'\n\[^\n]*leg-merge-4_c.C:10:\[0-9]*: note: during load of binding '::frob'$" }
+// { dg-regexp "\nIn module \[^\n]*leg-merge-4_b.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_b.H:5:\[0-9]*: error: conflicting type for imported declaration 'int frob\\(\\)'\nIn module \[^\n]*leg-merge-4_a.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_a.H:5:\[0-9]*: note: existing declaration 'void frob\\(\\)'\n\[^\n]*leg-merge-4_c.C:10:\[0-9]*: note: during load of binding '::frob'$" }
 
-// { dg-regexp "In module \[^\n]*leg-merge-4_b.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_b.H:6:\[0-9]*: error: conflicting global module declaration 'union X'\nIn module \[^\n]*leg-merge-4_a.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_a.H:6:\[0-9]*: note: existing declaration 'class X'\n\[^\n]*leg-merge-4_c.C:11:\[0-9]*: note: during load of binding '::X'$" }
+// { dg-regexp "In module \[^\n]*leg-merge-4_b.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_b.H:6:\[0-9]*: error: conflicting type for imported declaration 'union X'\nIn module \[^\n]*leg-merge-4_a.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_a.H:6:\[0-9]*: note: existing declaration 'class X'\n\[^\n]*leg-merge-4_c.C:11:\[0-9]*: note: during load of binding '::X'$" }