I've come up with the attached patch to fix an ICE and clean up error checking for "declare variant", primarily related to the C front end handling of unprototyped functions. I've tested on x86_64-linux-gnu; I've started a build for AMD offload testing but that won't be finished until tomorrow. Assuming no problems there, OK to commit?

-Sandra
From 3b0ea4a2768d21c22deadb2f0e7ad5e617f59849 Mon Sep 17 00:00:00 2001
From: Sandra Loosemore <sloosem...@baylibre.com>
Date: Sun, 10 Aug 2025 02:31:29 +0000
Subject: [PATCH] OpenMP: Improve front-end error-checking for "declare
 variant"

This patch fixes a number of problems with parser error checking of
"declare variant", especially in the C front end.

The new C testcase unprototyped-variant.c added by this patch used to
ICE when gimplifying the call site, at least in part because the
variant was being recorded even after it was diagnosed as invalid.
There was also a large block of dead code in the C front end that was
supposed to fix up an unprototyped declaration of a variant function
to match the base function declaration, that was never executed because
it was nested in a conditional that could never be true.  I've fixed those
problems by rearranging the code and only recording the variant if it
passes the correctness checks.  I also tried to add some comments and
re-work some particularly confusing bits of code, so that it's easier to
understand.

The OpenMP specification doesn't say what the behavior of "declare
variant" with the "append_args" clause should be when the base
function is unprototyped.  The additional arguments are supposed to be
inserted between the last fixed argument of the base function and any
varargs, but without a prototype, for any given call we have no idea
which arguments are fixed and which are varargs, and therefore no idea
where to insert the additional arguments.  This used to trigger some
other diagnostics (which one depending on whether the variant was also
unprototyped), but I thought it was better to just reject this with an
explicit "sorry".

Finally, I also observed that a missing "match" clause was only
rejected if "append_args" or "adjust_args" was present.  Per the spec,
"match" has the "required" property, so if it's missing it should be
diagnosed unconditionally.  The C++ and Fortran front ends had the same
issue so I fixed this one there too.

gcc/c/ChangeLog
	* c-parser.cc (c_finish_omp_declare_variant): Rework diagnostic
	code.  Do not record variant if there are errors.  Make check for
	a missing "match" clause unconditional.

gcc/cp/ChangeLog
	* parser.cc (cp_finish_omp_declare_variant): Structure diagnostic
	code similarly to C front end.  Make check for a missing "match"
	clause unconditional.

gcc/fortran/ChangeLog
	* openmp.cc (gfc_match_omp_declare_variant): Make check for a
	missing "match" clause unconditional.

gcc/testsuite/ChangeLog
	* g++.dg/gomp/adjust-args-1.C: Adjust expected output.
	* g++.dg/gomp/adjust-args-3.C: Likewise.
	* gcc.dg/gomp/adjust-args-1.c: Likewise:
	* gcc.dg/gomp/append-args-1.c: Likewise.
	* gcc.dg/gomp/unprototyped-variant.c: New.
	* gfortran.dg/gomp/adjust-args-1.f90: Adjust expected output.
	* gfortran.dg/gomp/append_args-1.f90: Likewise.
---
 gcc/c/c-parser.cc                             | 298 +++++++++---------
 gcc/cp/parser.cc                              |  56 ++--
 gcc/fortran/openmp.cc                         |   8 +-
 gcc/testsuite/g++.dg/gomp/adjust-args-1.C     |   2 +-
 gcc/testsuite/g++.dg/gomp/adjust-args-3.C     |   2 +-
 gcc/testsuite/gcc.dg/gomp/adjust-args-1.c     |   2 +-
 gcc/testsuite/gcc.dg/gomp/append-args-1.c     |  28 +-
 .../gcc.dg/gomp/unprototyped-variant.c        |  30 ++
 .../gfortran.dg/gomp/adjust-args-1.f90        |   2 +-
 .../gfortran.dg/gomp/append_args-1.f90        |   4 +-
 10 files changed, 238 insertions(+), 194 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/gomp/unprototyped-variant.c

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 4a13fc0d384..f1495f51e65 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -27185,6 +27185,24 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
       undeclared_variable (token->location, token->value);
       variant = error_mark_node;
     }
+  else if (TREE_CODE (variant) != FUNCTION_DECL)
+    {
+      error_at (token->location, "variant %qD is not a function",
+		variant);
+      variant = error_mark_node;
+    }
+  else if (fndecl_built_in_p (variant)
+	   && (strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)),
+			"__builtin_", strlen ("__builtin_")) == 0
+	       || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)),
+			   "__sync_", strlen ("__sync_")) == 0
+	       || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)),
+			   "__atomic_", strlen ("__atomic_")) == 0))
+    {
+      error_at (token->location, "variant %qD is a built-in",
+		variant);
+      variant = error_mark_node;
+    }
 
   c_parser_consume_token (parser);
 
@@ -27258,30 +27276,6 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
 	    goto fail;
 	  ctx = omp_check_context_selector (match_loc, ctx,
 					    OMP_CTX_DECLARE_VARIANT);
-	  if (ctx != error_mark_node && variant != error_mark_node)
-	    {
-	      if (TREE_CODE (variant) != FUNCTION_DECL)
-		{
-		  error_at (token->location, "variant %qD is not a function",
-			    variant);
-		  variant = error_mark_node;
-		}
-	      else if (fndecl_built_in_p (variant)
-		       && (strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)),
-				    "__builtin_", strlen ("__builtin_"))
-			     == 0
-			   || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)),
-				       "__sync_", strlen ("__sync_"))
-				== 0
-			   || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)),
-				       "__atomic_", strlen ("__atomic_"))
-				== 0))
-		{
-		  error_at (token->location, "variant %qD is a built-in",
-			    variant);
-		  variant = error_mark_node;
-		}
-	    }
 	}
       else if (ccode == adjust_args)
 	{
@@ -27423,18 +27417,62 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
 
       parens.require_close (parser);
   } while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL));
+  if (variant != error_mark_node && !has_match)
+    {
+      c_parser_error (parser, "expected %<match%> clause");
+      variant = error_mark_node;
+    }
   c_parser_skip_to_pragma_eol (parser);
 
-  if ((ctx != error_mark_node && variant != error_mark_node)
+  /* At this point, we have completed parsing of the pragma, now it's
+     on to error checking.  */
+  if (variant == error_mark_node || ctx == error_mark_node)
+    /* Previously diagnosed error.  */
+    return;
+
+  if ((has_adjust_args || append_args_tree)
       && !omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT,
-				    OMP_TRAIT_CONSTRUCT_SIMD))
+				    OMP_TRAIT_CONSTRUCT_DISPATCH))
     {
-      bool fail = false;
-      if (append_args_tree)
+      error_at (has_adjust_args ? adjust_args_loc : append_args_loc,
+		"an %qs clause can only be specified if the "
+		"%<dispatch%> selector of the %<construct%> selector "
+		"set appears in the %<match%> clause",
+		has_adjust_args ? "adjust_args" : "append_args");
+      return;
+    }
+
+  if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT,
+				 OMP_TRAIT_CONSTRUCT_SIMD))
+    /* Check that the base and variant have compatible types.  */
+    {
+      tree base_type = TREE_TYPE (fndecl);
+      tree variant_type = TREE_TYPE (variant);
+      bool unprototyped_variant
+	= (TYPE_ARG_TYPES (variant_type) == NULL_TREE
+	   && !TYPE_NO_NAMED_ARGS_STDARG_P (variant_type));
+
+      if (append_args_tree
+	  && TYPE_ARG_TYPES (base_type) == NULL_TREE
+	  && !TYPE_NO_NAMED_ARGS_STDARG_P (base_type))
 	{
+	  /* The base function is a pre-C23 unprototyped function.  Without
+	     a prototype, we don't know the offset where the append_args go.
+	     That offset needs to be stored with the append_args in the
+	     variant function attributes, so we cannot presently handle
+	     this case.  */
+	  sorry_at (append_args_loc,
+		    "%<append_args%> with unprototyped base function "
+		    "is not supported yet");
+	  return;
+	}
+      else if (append_args_tree)
+	{
+	  /* Find nbase_args, the number of fixed arguments in the base
+	     function.  */
 	  int nappend_args = 0;
 	  int nbase_args = 0;
-	  for (tree t = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+	  for (tree t = TYPE_ARG_TYPES (base_type);
 	       t && TREE_VALUE (t) != void_type_node; t = TREE_CHAIN (t))
 	    nbase_args++;
 	  for (tree t = append_args_tree; t; t = TREE_CHAIN (t))
@@ -27445,135 +27483,111 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
 	  append_args_tree = build_tree_list (build_int_cst (integer_type_node,
 							     nbase_args),
 					      append_args_tree);
-	  tree args, arg;
-	  args = arg = TYPE_ARG_TYPES (TREE_TYPE (variant));
-	  for (int j = 0; j < nbase_args && arg; j++, arg = TREE_CHAIN (arg))
-	    args = arg;
-	  for (int i = 0; i < nappend_args && arg; i++)
-	    arg = TREE_CHAIN (arg);
-	  tree saved_args;
-	  if (nbase_args && args)
+
+	  /* Give a specific diagnostic if the append_args parameters
+	     of the variant are of the wrong type, or missing.  The
+	     compatible types test below could fail to detect this if
+	     the variant is a varargs function.  */
+	  if (!unprototyped_variant)
 	    {
-	      saved_args = TREE_CHAIN (args);
-	      TREE_CHAIN (args) = arg;
+	      tree args = TYPE_ARG_TYPES (variant_type);
+	      for (int i = 0; args && i < nbase_args;
+		   i++, args = TREE_CHAIN (args))
+		;
+	      for (int i = 0; i < nappend_args; i++, args = TREE_CHAIN (args))
+		if (!args || !c_omp_interop_t_p (TREE_VALUE (args)))
+		  {
+		    error_at (DECL_SOURCE_LOCATION (variant),
+			      "argument %d of %qD must be of "
+			      "%<omp_interop_t%>",
+			      nbase_args + i + 1, variant);
+		    inform (append_args_loc,
+			    "%<append_args%> specified here");
+		    return;
+		  }
 	    }
-	  else
+
+	  /* Perform the "implementation defined transformation" on the type
+	     of the base function to add the append_args before checking it
+	     for compatibility with the function variant's type.  */
+	  tree args = TYPE_ARG_TYPES (base_type);
+	  tree newargs = NULL_TREE;
+	  tree lastarg = NULL_TREE;
+	  for (int j = 0; j < nbase_args; j++, args = TREE_CHAIN (args))
 	    {
-	      saved_args = args;
-	      TYPE_ARG_TYPES (TREE_TYPE (variant)) = arg;
-	      TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (variant)) = 1;
+	      tree t = tree_cons (TREE_PURPOSE (args),
+				  TREE_VALUE (args), NULL_TREE);
+	      if (lastarg)
+		TREE_CHAIN (lastarg) = t;
+	      else
+		newargs = t;
+	      lastarg = t;
 	    }
-	  if (!comptypes (TREE_TYPE (fndecl), TREE_TYPE (variant)))
-	    fail = true;
-	  if (nbase_args && args)
-	    TREE_CHAIN (args) = saved_args;
-	  else
+	  tree type = lookup_name (get_identifier ("omp_interop_t"));
+	  type = type ? TREE_TYPE (type) : pointer_sized_int_node;
+	  for (int j = 0; j < nappend_args; j++)
 	    {
-	      TYPE_ARG_TYPES (TREE_TYPE (variant)) = saved_args;
-	      TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (variant)) = 0;
+	      tree t = tree_cons (NULL_TREE, type, NULL_TREE);
+	      if (lastarg)
+		TREE_CHAIN (lastarg) = t;
+	      else
+		newargs = t;
+	      lastarg = t;
 	    }
-	  arg = saved_args;
-	  if (!fail)
-	    for (int i = 0; i < nappend_args; i++, arg = TREE_CHAIN (arg))
-	      if (!arg || !c_omp_interop_t_p (TREE_VALUE (arg)))
-		{
-		  error_at (DECL_SOURCE_LOCATION (variant),
-			    "argument %d of %qD must be of %<omp_interop_t%>",
-			    nbase_args + i + 1, variant);
-		  inform (append_args_loc, "%<append_args%> specified here");
-		  break;
-		}
+	  TREE_CHAIN (lastarg) = args;
+
+	  /* Temporarily stuff newargs into the original base_type.  */
+	  tree saveargs = TYPE_ARG_TYPES (base_type);
+	  TYPE_ARG_TYPES (base_type) = newargs;
+	  bool fail = !comptypes (base_type, variant_type);
+	  TYPE_ARG_TYPES (base_type) = saveargs;
+
+	  if (fail)
+	    {
+	      error_at (token->location,
+			"variant %qD and base %qD have incompatible types "
+			"after %<append_args%> adjustment",
+			variant, fndecl);
+	      return;
+	    }
+	  else if (unprototyped_variant)
+	    /* If we've got an unprototyped variant, copy the transformed
+	       base arg types to the variant.  This is needed later by
+	       modify_call_for_omp_dispatch.  */
+	    TYPE_ARG_TYPES (variant_type) = newargs;
 	}
-      else
+      else  /* No append_args present.  */
 	{
-	  if (comptypes (TREE_TYPE (fndecl), TREE_TYPE (variant)))
+	  if (!comptypes (base_type, variant_type))
 	    {
-	      if (TYPE_ARG_TYPES (TREE_TYPE (variant)) == NULL_TREE
-		  && TYPE_ARG_TYPES (TREE_TYPE (fndecl)) != NULL_TREE)
-		{
-		  if (!append_args_tree)
-		    TYPE_ARG_TYPES (TREE_TYPE (variant))
-		      = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
-		  else
-		    {
-		      tree new_args = NULL_TREE;
-		      tree arg, last_arg = NULL_TREE;
-		      for (arg = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
-			   arg && arg != void_type_node; arg = TREE_CHAIN (arg))
-			{
-			  if (new_args == NULL_TREE)
-			    new_args = last_arg = copy_node (arg);
-			  else
-			    {
-			      TREE_CHAIN (last_arg) = copy_node (arg);
-			      last_arg = TREE_CHAIN (last_arg);
-			    }
-			}
-		      for (tree t3 = append_args_tree; t3; t3 = TREE_CHAIN (t3))
-			{
-			  tree type = lookup_name (get_identifier ("omp_interop_t"));
-			  type = type ? TREE_TYPE (type) : ptr_type_node;
-			  last_arg = tree_cons (NULL_TREE, type, last_arg);
-			}
-		      TREE_CHAIN (last_arg) = arg;
-		      TYPE_ARG_TYPES (TREE_TYPE (variant)) = new_args;
-		    }
-		}
+	      error_at (token->location,
+			"variant %qD and base %qD have incompatible types",
+			variant, fndecl);
+	      return;
 	    }
-	  else
-	    fail = true;
-	}
-      if (fail)
-	{
-	  error_at (token->location,
-		    "variant %qD and base %qD have incompatible types",
-		    variant, fndecl);
-	  variant = error_mark_node;
-	}
-    }
-  if (ctx != error_mark_node && variant != error_mark_node)
-    {
-      C_DECL_USED (variant) = 1;
-      tree construct = omp_get_context_selector_list (ctx,
-						      OMP_TRAIT_SET_CONSTRUCT);
-      omp_mark_declare_variant (match_loc, variant, construct);
-      if (omp_context_selector_matches (ctx, NULL_TREE, false))
-	{
-	  tree attr = tree_cons (get_identifier ("omp declare variant base"),
-				 build_tree_list (variant, ctx),
-				 DECL_ATTRIBUTES (fndecl));
-	  DECL_ATTRIBUTES (fndecl) = attr;
+	  else if (TYPE_ARG_TYPES (variant_type) == NULL_TREE
+		   && !TYPE_NO_NAMED_ARGS_STDARG_P (variant_type)
+		   && TYPE_ARG_TYPES (base_type) != NULL_TREE)
+	    /* If we've got an unprototyped variant but the base has
+	       a prototype, copy the base arg types to the variant.  */
+	    TYPE_ARG_TYPES (variant_type) = TYPE_ARG_TYPES (base_type);
 	}
     }
 
-  if (has_adjust_args || append_args_tree)
+  /* If we made it here, store the parsed information.  */
+  C_DECL_USED (variant) = 1;
+  tree construct = omp_get_context_selector_list (ctx,
+						  OMP_TRAIT_SET_CONSTRUCT);
+  omp_mark_declare_variant (match_loc, variant, construct);
+  if (omp_context_selector_matches (ctx, NULL_TREE, false))
     {
-      if (!has_match)
-	{
-	  error_at (has_adjust_args ? adjust_args_loc : append_args_loc,
-		    "an %qs clause requires a %<match%> clause",
-		    has_adjust_args ? "adjust_args" : "append_args");
-	}
-      else if (ctx != error_mark_node && variant != error_mark_node)
-	{
-	  tree attr = lookup_attribute ("omp declare variant base",
-					DECL_ATTRIBUTES (fndecl));
-	  if (attr != NULL_TREE)
-	    {
-	      tree ctx = TREE_VALUE (TREE_VALUE (attr));
-	      if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT,
-					     OMP_TRAIT_CONSTRUCT_DISPATCH))
-		error_at (has_adjust_args ? adjust_args_loc : append_args_loc,
-			  "an %qs clause can only be specified if the "
-			  "%<dispatch%> selector of the %<construct%> selector "
-			  "set appears in the %<match%> clause",
-			  has_adjust_args ? "adjust_args" : "append_args");
-	    }
-	}
+      tree attr = tree_cons (get_identifier ("omp declare variant base"),
+			     build_tree_list (variant, ctx),
+			     DECL_ATTRIBUTES (fndecl));
+      DECL_ATTRIBUTES (fndecl) = attr;
     }
 
-  if ((ctx != error_mark_node && variant != error_mark_node)
-      && (need_device_ptr_list || append_args_tree))
+  if (need_device_ptr_list || append_args_tree)
     {
       tree variant_decl = tree_strip_nop_conversions (variant);
       tree t = build_tree_list (need_device_ptr_list,
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 860f3f0edaf..648a36d8a9d 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -51049,41 +51049,41 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok,
 					      append_args_tree);
 	}
   } while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL));
-
-  if ((ctx != error_mark_node && variant != error_mark_node)
-      && (has_adjust_args || append_args_tree))
+  if (variant != error_mark_node && !has_match)
     {
-      if (!has_match)
+      cp_parser_error (parser, "expected %<match%> clause");
+      variant = error_mark_node;
+    }
+  cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+
+  /* At this point, we have completed parsing of the pragma, now it's
+     on to error checking.  */
+  if (variant == error_mark_node || ctx == error_mark_node)
+    /* Previously diagnosed error.  */
+    return attrs;
+
+  if (has_adjust_args || append_args_tree)
+    {
+      if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT,
+				     OMP_TRAIT_CONSTRUCT_DISPATCH))
 	{
 	  error_at (has_adjust_args ? adjust_args_loc : append_args_loc,
-		    "an %qs clause requires a %<match%> clause",
+		    "an %qs clause can only be specified if the %<dispatch%> "
+		    "selector of the construct selector set appears "
+		    "in the %<match%> clause",
 		    has_adjust_args ? "adjust_args" : "append_args");
+	  return attrs;
 	}
-      else
-	{
-	  gcc_assert (TREE_PURPOSE (attrs)
-		      == get_identifier ("omp declare variant base"));
-	  gcc_assert (TREE_PURPOSE (TREE_VALUE (attrs)) == variant);
-	  ctx = TREE_VALUE (TREE_VALUE (attrs));
-	  if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT,
-					 OMP_TRAIT_CONSTRUCT_DISPATCH))
-	    error_at (has_adjust_args ? adjust_args_loc : append_args_loc,
-		      "an %qs clause can only be specified if the %<dispatch%> "
-		      "selector of the construct selector set appears "
-		      "in the %<match%> clause",
-		      has_adjust_args ? "adjust_args" : "append_args");
-	  // We might not have a DECL for the variant yet. So we store the
-	  // need_device_ptr list in the base function attribute, after loc
-	  // nodes.
-	  tree t = build_tree_list (need_device_ptr_list,
-				    NULL_TREE /* need_device_addr */);
-	  TREE_CHAIN (t) = append_args_tree;
-	  TREE_VALUE (attrs) = chainon (TREE_VALUE (attrs),
-					build_tree_list ( NULL_TREE, t));
-	}
+      // We might not have a DECL for the variant yet. So we store the
+      // need_device_ptr list in the base function attribute, after loc
+      // nodes.
+      tree t = build_tree_list (need_device_ptr_list,
+				NULL_TREE /* need_device_addr */);
+      TREE_CHAIN (t) = append_args_tree;
+      TREE_VALUE (attrs) = chainon (TREE_VALUE (attrs),
+				    build_tree_list (NULL_TREE, t));
     }
 
-  cp_parser_skip_to_pragma_eol (parser, pragma_tok);
   return attrs;
 }
 
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index f1acc00f561..066d4985852 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -6982,13 +6982,9 @@ gfc_match_omp_declare_variant (void)
       return MATCH_ERROR;
     }
 
-  if ((has_adjust_args || has_append_args) && !has_match)
+  if (!has_match)
     {
-      gfc_error ("the %qs clause at %L can only be specified if the "
-		 "%<dispatch%> selector of the construct selector set appears "
-		 "in the %<match%> clause",
-		 has_adjust_args ? "adjust_args" : "append_args",
-		 has_adjust_args ?  &adjust_args_loc : &append_args_loc);
+      gfc_error ("expected %<match%> at %C");
       return MATCH_ERROR;
     }
 
diff --git a/gcc/testsuite/g++.dg/gomp/adjust-args-1.C b/gcc/testsuite/g++.dg/gomp/adjust-args-1.C
index 29fde1464f4..681b3854996 100644
--- a/gcc/testsuite/g++.dg/gomp/adjust-args-1.C
+++ b/gcc/testsuite/g++.dg/gomp/adjust-args-1.C
@@ -17,7 +17,7 @@ int f2b (void *a);
 int f2c (void *a);
 #pragma omp declare variant (f1) match (construct={dispatch}) adjust_args (other: a) /* { dg-error "expected 'nothing' or 'need_device_ptr'" } */
 int f3 (int a);
-#pragma omp declare variant (f0) adjust_args (nothing: a) /* { dg-error "an 'adjust_args' clause requires a 'match' clause" } */
+#pragma omp declare variant (f0) adjust_args (nothing: a) /* { dg-error "expected 'match' clause" } */
 int f4 (void *a);
 #pragma omp declare variant (f1) match (construct={dispatch}) adjust_args () /* { dg-error "expected 'nothing' or 'need_device_ptr' followed by ':'" } */
 int f5 (int a);
diff --git a/gcc/testsuite/g++.dg/gomp/adjust-args-3.C b/gcc/testsuite/g++.dg/gomp/adjust-args-3.C
index 3f9a0cd0071..bba472e4144 100644
--- a/gcc/testsuite/g++.dg/gomp/adjust-args-3.C
+++ b/gcc/testsuite/g++.dg/gomp/adjust-args-3.C
@@ -2,5 +2,5 @@
 // clause is missing.
 
 void f(int *, int *, int *);
-#pragma omp declare variant(f) adjust_args(need_device_ptr: xxx)  /* { dg-error "an 'adjust_args' clause requires a 'match' clause" } */
+#pragma omp declare variant(f) adjust_args(need_device_ptr: xxx)  /* { dg-error "expected 'match' clause" } */
 void g(int *xxx, int *yyy, int *zzz);
diff --git a/gcc/testsuite/gcc.dg/gomp/adjust-args-1.c b/gcc/testsuite/gcc.dg/gomp/adjust-args-1.c
index 90787ef2f9d..d67db5e60ca 100644
--- a/gcc/testsuite/gcc.dg/gomp/adjust-args-1.c
+++ b/gcc/testsuite/gcc.dg/gomp/adjust-args-1.c
@@ -11,7 +11,7 @@ int f1 (int);
 int f2 (void *a);
 #pragma omp declare variant (f1) match (construct={dispatch}) adjust_args (other: a) /* { dg-error "expected 'nothing' or 'need_device_ptr'" } */
 int f3 (int a);
-#pragma omp declare variant (f0) adjust_args (nothing: a) /* { dg-error "an 'adjust_args' clause requires a 'match' clause" } */
+#pragma omp declare variant (f0) adjust_args (nothing: a) /* { dg-error "expected 'match' clause" } */
 int f4 (void *a);
 #pragma omp declare variant (f1) match (construct={dispatch}) adjust_args () /* { dg-error "expected 'nothing' or 'need_device_ptr' followed by ':'" } */
 int f5 (int a);
diff --git a/gcc/testsuite/gcc.dg/gomp/append-args-1.c b/gcc/testsuite/gcc.dg/gomp/append-args-1.c
index 81dd1061aa1..15fc7527c3b 100644
--- a/gcc/testsuite/gcc.dg/gomp/append-args-1.c
+++ b/gcc/testsuite/gcc.dg/gomp/append-args-1.c
@@ -15,56 +15,60 @@ typedef enum omp_interop_t
 } omp_interop_t;
 
 
-/* (A) No prototype for the variant but for the base function.  */
+/* (A) No prototype for the variant but for the base function.
+   This is OK, the unprototyped decl is compatible with the modified
+   argument list.  */
 
 void variant_fn1();
 #pragma omp declare variant(variant_fn1) match(construct={dispatch}) append_args(interop(target)) \
                                          adjust_args(need_device_ptr: x,y)
 void bar1(int *x, int *y);
-/* { dg-error "variant 'variant_fn1' and base 'bar1' have incompatible types" "" { target *-*-* } .-3 }  */
 
 
 void variant_fn2();
 #pragma omp declare variant(variant_fn2) match(construct={dispatch}) append_args(interop(target))
 void bar2(int *x, int *y);
-/* { dg-error "variant 'variant_fn2' and base 'bar2' have incompatible types" "" { target *-*-* } .-2 }  */
 
 
 
-/* (B) No prototype for the variant nor for the base function.  */
+/* (B) No prototype for the variant nor for the base function.
+   The declarations are compatible, but adjust_args requires a prototyped
+   base function so that we know where in the arglist to insert the additional
+   omp_interop_t arguments.  */
 
-void variant_fn3();  /* { dg-error "argument 1 of 'variant_fn3' must be of 'omp_interop_t'" }  */
+void variant_fn3();
 #pragma omp declare variant(variant_fn3) match(construct={dispatch}) append_args(interop(target)) \
                                          adjust_args(need_device_ptr: x,y)
 void bar3();
 /* { dg-error "'x' undeclared here \\(not in a function\\)" "" { target *-*-* } .-2 }  */
 /* { dg-error "'y' undeclared here \\(not in a function\\)" "" { target *-*-* } .-3 }  */
-/* { dg-note "'append_args' specified here" "" { target *-*-* } .-5 }  */
+/* { dg-message "'append_args' with unprototyped base function" "" { target *-*-* } .-5 }  */
 
 
-void variant_fn4();  /* { dg-error "argument 1 of 'variant_fn4' must be of 'omp_interop_t'" }  */
+void variant_fn4();
 #pragma omp declare variant(variant_fn4) match(construct={dispatch}) append_args(interop(target))
 void bar4();
-/* { dg-note "'append_args' specified here" "" { target *-*-* } .-2 }  */
+/* { dg-message "'append_args' with unprototyped base function" "" { target *-*-* } .-2 }  */
 
 
 
-/* (C) Only a prototype on the variant-function side.  */
+/* (C) Only a prototype on the variant-function side.  Again, the base
+   function requires a prototype with append_args.  */
 
 void variant_fn5(omp_interop_t, omp_interop_t);
 #pragma omp declare variant(variant_fn5) match(construct={dispatch}) append_args(interop(target)) \
                                          adjust_args(need_device_ptr: x,y)
 void bar5();
-/* { dg-error "variant 'variant_fn5' and base 'bar5' have incompatible types" "" { target *-*-* } .-3 }  */
+/* { dg-message "'append_args' with unprototyped base function" "" { target *-*-* } .-3 }  */
 
 
 void variant_fn6(omp_interop_t, omp_interop_t);
 #pragma omp declare variant(variant_fn6) match(construct={dispatch}) append_args(interop(target))
 void bar6();
-/* { dg-error "variant 'variant_fn6' and base 'bar6' have incompatible types" "" { target *-*-* } .-2 }  */
+/* { dg-message "'append_args' with unprototyped base function" "" { target *-*-* } .-2 }  */
 
 
 void variant_fn7(int *, int, omp_interop_t, omp_interop_t);
 #pragma omp declare variant(variant_fn7) match(construct={dispatch}) append_args(interop(target))
 void bar7();
-/* { dg-error "variant 'variant_fn7' and base 'bar7' have incompatible types" "" { target *-*-* } .-2 }  */
+/* { dg-message "'append_args' with unprototyped base function" "" { target *-*-* } .-2 }  */
diff --git a/gcc/testsuite/gcc.dg/gomp/unprototyped-variant.c b/gcc/testsuite/gcc.dg/gomp/unprototyped-variant.c
new file mode 100644
index 00000000000..ca84775bbd1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/unprototyped-variant.c
@@ -0,0 +1,30 @@
+/* { dg-additional-options "-std=gnu90" } */
+
+/* This test case used to ICE in the gimplifier after issuing a 
+   different diagnostic message.  */
+
+#if __cplusplus >= 201103L
+# define __GOMP_UINTPTR_T_ENUM : __UINTPTR_TYPE__
+#else
+# define __GOMP_UINTPTR_T_ENUM
+#endif
+
+typedef enum omp_interop_t __GOMP_UINTPTR_T_ENUM
+{
+  omp_interop_none = 0,
+  __omp_interop_t_max__ = __UINTPTR_MAX__
+} omp_interop_t;
+
+
+void g2();
+#pragma omp declare variant(g2) match(construct={dispatch}) append_args(interop(target,targetsync))  /* { dg-message "'append_args' with unprototyped base function" } */
+void f2();
+
+void foo()
+{
+  omp_interop_t obj6 = omp_interop_none;
+  const char *cp = 0L;
+
+  #pragma omp dispatch interop(obj6)
+     f2(5, cp);
+}
diff --git a/gcc/testsuite/gfortran.dg/gomp/adjust-args-1.f90 b/gcc/testsuite/gfortran.dg/gomp/adjust-args-1.f90
index 39824c29701..f198ce05b87 100644
--- a/gcc/testsuite/gfortran.dg/gomp/adjust-args-1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/adjust-args-1.f90
@@ -26,7 +26,7 @@ module main
       integer function f4 (a)
          import c_ptr
          type(c_ptr), intent(inout) :: a
-         !$omp declare variant (f0) adjust_args (nothing: a) ! { dg-error "the 'adjust_args' clause at .1. can only be specified if the 'dispatch' selector of the construct selector set appears in the 'match' clause" }
+         !$omp declare variant (f0) adjust_args (nothing: a) ! { dg-error "expected 'match' at .1." } 
       end function
       integer function f5 (i)
          integer, intent(inout) :: i
diff --git a/gcc/testsuite/gfortran.dg/gomp/append_args-1.f90 b/gcc/testsuite/gfortran.dg/gomp/append_args-1.f90
index 7e4f74d281c..9ed6e2d9923 100644
--- a/gcc/testsuite/gfortran.dg/gomp/append_args-1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/append_args-1.f90
@@ -56,12 +56,12 @@ contains
 
   subroutine f2b ()
     !$omp declare variant (f1c)  &
-    !$omp&     append_args ( interop ( target , targetsync) )   ! { dg-error "the 'append_args' clause at .1. can only be specified if the 'dispatch' selector of the construct selector set appears in the 'match' clause" } 
+    !$omp&     append_args ( interop ( target , targetsync) )   ! { dg-error "expected 'match'" } 
   end subroutine
 
   subroutine f2c (x,y)
     !$omp declare variant (fop) , append_args ( interop ( target, prefer_type ( "cuda", "hip" ) ) , interop(target)) , &
-    !$omp&     adjust_args (need_device_ptr : x, y )   ! { dg-error "the 'adjust_args' clause at .1. can only be specified if the 'dispatch' selector of the construct selector set appears in the 'match' clause" } 
+    !$omp&     adjust_args (need_device_ptr : x, y )   ! { dg-error "expected 'match' at .1." } 
     type(c_ptr) :: x, y
     value :: y
   end subroutine
-- 
2.39.5

Reply via email to