]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
OpenMP: Improve front-end error-checking for "declare variant"
authorSandra Loosemore <sloosemore@baylibre.com>
Mon, 25 Aug 2025 01:43:49 +0000 (01:43 +0000)
committerSandra Loosemore <sloosemore@baylibre.com>
Tue, 26 Aug 2025 23:39:22 +0000 (23:39 +0000)
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
* c-c++-common/gomp/append-args-1.c: Adjust expected output.
* g++.dg/gomp/adjust-args-1.C: Likewise.
* 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
gcc/cp/parser.cc
gcc/fortran/openmp.cc
gcc/testsuite/c-c++-common/gomp/append-args-1.c
gcc/testsuite/g++.dg/gomp/adjust-args-1.C
gcc/testsuite/g++.dg/gomp/adjust-args-3.C
gcc/testsuite/gcc.dg/gomp/adjust-args-1.c
gcc/testsuite/gcc.dg/gomp/append-args-1.c
gcc/testsuite/gcc.dg/gomp/unprototyped-variant.c [new file with mode: 0644]
gcc/testsuite/gfortran.dg/gomp/adjust-args-1.f90
gcc/testsuite/gfortran.dg/gomp/append_args-1.f90

index e8b64948bf69ce8210bd1f184545e469a923d8b3..db669242d58a06504f142288813f851952146d99 100644 (file)
@@ -27304,6 +27304,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);
 
@@ -27377,30 +27395,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)
        {
@@ -27542,18 +27536,64 @@ 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");
+         inform (DECL_SOURCE_LOCATION (fndecl),
+                 "base function %qD declared here", fndecl);
+         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))
@@ -27564,135 +27604,117 @@ 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)
-           {
-             saved_args = TREE_CHAIN (args);
-             TREE_CHAIN (args) = arg;
+
+         /* 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)
+           {
+             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;
-               }
-       }
-      else
-       {
-         if (comptypes (TREE_TYPE (fndecl), TREE_TYPE (variant)))
+         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)
            {
-             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 "
+                       "after %<append_args%> adjustment",
+                       variant, fndecl);
+             inform (DECL_SOURCE_LOCATION (variant),
+                     "%<declare variant%> candidate %qD declared here",
+                     variant);
+             return;
            }
-         else
-           fail = true;
+         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;
        }
-      if (fail)
+      else  /* No append_args present.  */
        {
-         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;
+         if (!comptypes (base_type, variant_type))
+           {
+             error_at (token->location,
+                       "variant %qD and base %qD have incompatible types",
+                       variant, fndecl);
+             inform (DECL_SOURCE_LOCATION (variant),
+                     "%<declare variant%> candidate %qD declared here",
+                     variant);
+             return;
+           }
+         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,
index 9d4f5564c367d538f9f722f0161033565007ff09..0d45ab4279921ccaeae17163de4e5308de53e008 100644 (file)
@@ -51642,41 +51642,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 (variant != error_mark_node && !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 ((ctx != error_mark_node && variant != error_mark_node)
-      && (has_adjust_args || append_args_tree))
+  if (has_adjust_args || append_args_tree)
     {
-      if (!has_match)
+      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;
 }
 
index f1acc00f561b15272e51c1652e49fd53d7097747..9e282c7b9f127490d17f67eecba5cf7413508a53 100644 (file)
@@ -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%> clause at %C");
       return MATCH_ERROR;
     }
 
index e8561a57b1d30d1788213a10c1ca56511f06a99f..018a807c1fb64c7aa01387cdc7563de021016619 100644 (file)
@@ -42,7 +42,7 @@ float repl4(short, short, omp_interop_t, short);
 float base4(short, short);
 /* { dg-error "variant 'repl4' and base 'base4' have incompatible types" "" { target c } .-2 }  */
 /* { dg-error "too few arguments to function 'float repl4\\(short int, short int, omp_interop_t, short int\\)'" "" { target c++ } .-3 }  */
-/* { dg-note "declared here" "" { target c++ } .-5 } */
+/* { dg-note "declared here" "" { target *-*-*} .-5 } */
 
 
 float repl5(short, short, omp_interop_t, short);
@@ -58,7 +58,7 @@ float repl6(short, short, omp_interop_t, short);
 float base6(short, short);
 /* { dg-error "variant 'repl6' and base 'base6' have incompatible types" "" { target c } .-2 }  */
 /* { dg-error "too few arguments to function 'float repl6\\(short int, short int, omp_interop_t, short int\\)'" "" { target c++ } .-3 }  */
-/* { dg-note "declared here" "" { target c++ } .-5 } */
+/* { dg-note "declared here" "" { target *-*-*} .-5 } */
 
 
 float
index 29fde1464f4420567e9df5401011dec3f612771c..681b3854996f9884a3daa5c544d83ffc93332279 100644 (file)
@@ -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);
index 3f9a0cd0071321d17b9d03238ceaa86387bdc961..bba472e41446710c00623a786a398254e2e93954 100644 (file)
@@ -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);
index 90787ef2f9d9a0a0817bbbd65d27077c35eb310b..d67db5e60ca61dcd96aae3f3b14884e8530633bc 100644 (file)
@@ -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);
index 81dd1061aa15c2d7ba50a943f271814d8379909c..15fc7527c3baf633f8005d76968dc2602d2c9abf 100644 (file)
@@ -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 (file)
index 0000000..ca84775
--- /dev/null
@@ -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);
+}
index 39824c297019cedd0e0d18384d890349bacaeba7..3a6711b83cf40fae9a2593a31873657293d9c04e 100644 (file)
@@ -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' clause at .1." } 
       end function
       integer function f5 (i)
          integer, intent(inout) :: i
index 7e4f74d281c52e56b21bdb25d9ff0ad7bbf49d18..fdab51fe387e64aa43c95bb5e6ffb81c2fd6e45c 100644 (file)
@@ -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' clause at .1." } 
     type(c_ptr) :: x, y
     value :: y
   end subroutine