@@ -3112,8 +3112,8 @@ const struct c_omp_directive c_omp_direc
C_OMP_DIR_STANDALONE, false },
{ "begin", "assumes", nullptr, PRAGMA_OMP_BEGIN,
C_OMP_DIR_INFORMATIONAL, false },
- /* { "begin", "declare", "target", PRAGMA_OMP_BEGIN,
- C_OMP_DIR_DECLARATIVE, false }, */
+ { "begin", "declare", "target", PRAGMA_OMP_BEGIN,
+ C_OMP_DIR_DECLARATIVE, false },
/* { "begin", "declare", "variant", PRAGMA_OMP_BEGIN,
C_OMP_DIR_DECLARATIVE, false }, */
/* { "begin", "metadirective", nullptr, PRAGMA_OMP_BEGIN,
@@ -60,9 +60,14 @@ struct GTY(()) language_function {
int warn_about_return_type;
};
+struct GTY(()) c_omp_declare_target_attr {
+ int device_type;
+};
+
/* If non-zero, implicit "omp declare target" attribute is added into the
attribute lists. */
-extern GTY(()) int current_omp_declare_target_attribute;
+extern GTY(()) vec<c_omp_declare_target_attr, va_gc>
+ *current_omp_declare_target_attribute;
/* Similarly whether we are in between #pragma omp begin assumes and
#pragma omp end assumes (and how many times when nested). */
extern GTY(()) int current_omp_begin_assumes;
@@ -1675,18 +1675,22 @@ c_parser_translation_unit (c_parser *par
if (DECL_SIZE (decl) == NULL_TREE && TREE_TYPE (decl) != error_mark_node)
error ("storage size of %q+D isn%'t known", decl);
- if (current_omp_declare_target_attribute)
+ if (vec_safe_length (current_omp_declare_target_attribute))
{
+ c_omp_declare_target_attr
+ a = current_omp_declare_target_attribute->pop ();
if (!errorcount)
- error ("%<#pragma omp declare target%> without corresponding "
- "%<#pragma omp end declare target%>");
- current_omp_declare_target_attribute = 0;
+ error ("%qs without corresponding %qs",
+ a.device_type >= 0 ? "#pragma omp begin declare target"
+ : "#pragma omp declare target",
+ "#pragma omp end declare target");
+ vec_safe_truncate (current_omp_declare_target_attribute, 0);
}
if (current_omp_begin_assumes)
{
if (!errorcount)
- error ("%<#pragma omp begin assumes%> without corresponding "
- "%<#pragma omp end assumes%>");
+ error ("%qs without corresponding %qs",
+ "#pragma omp begin assumes", "#pragma omp end assumes");
current_omp_begin_assumes = 0;
}
}
@@ -16818,8 +16822,8 @@ c_parser_omp_clause_device_type (c_parse
else
goto invalid_kind;
- /* check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE_TYPE,
- "device_type"); */
+ check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE_TYPE,
+ "device_type");
c_parser_consume_token (parser);
parens.skip_until_found_close (parser);
c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE_TYPE);
@@ -22351,7 +22355,8 @@ c_parser_omp_declare_target (c_parser *p
else
{
c_parser_skip_to_pragma_eol (parser);
- current_omp_declare_target_attribute++;
+ c_omp_declare_target_attr attr = { -1 };
+ vec_safe_push (current_omp_declare_target_attribute, attr);
return;
}
for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
@@ -22429,12 +22434,17 @@ c_parser_omp_declare_target (c_parser *p
}
}
if (device_type && only_device_type)
- warning_at (OMP_CLAUSE_LOCATION (clauses), 0,
- "directive with only %<device_type%> clauses ignored");
+ error_at (OMP_CLAUSE_LOCATION (clauses),
+ "directive with only %<device_type%> clause");
}
/* OpenMP 5.1
- #pragma omp begin assumes clauses[optseq] new-line */
+ #pragma omp begin assumes clauses[optseq] new-line
+
+ #pragma omp begin declare target clauses[optseq] new-line */
+
+#define OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK \
+ (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE)
static void
c_parser_omp_begin (c_parser *parser)
@@ -22443,7 +22453,33 @@ c_parser_omp_begin (c_parser *parser)
c_parser_consume_pragma (parser);
if (c_parser_next_token_is (parser, CPP_NAME))
p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
- if (strcmp (p, "assumes") == 0)
+ if (strcmp (p, "declare") == 0)
+ {
+ c_parser_consume_token (parser);
+ p = "";
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "target") == 0)
+ {
+ c_parser_consume_token (parser);
+ tree clauses
+ = c_parser_omp_all_clauses (parser,
+ OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK,
+ "#pragma omp begin declare target");
+ int device_type = 0;
+ for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE)
+ device_type |= OMP_CLAUSE_DEVICE_TYPE_KIND (c);
+ c_omp_declare_target_attr attr = { device_type };
+ vec_safe_push (current_omp_declare_target_attribute, attr);
+ }
+ else
+ {
+ c_parser_error (parser, "expected %<target%>");
+ c_parser_skip_to_pragma_eol (parser);
+ }
+ }
+ else if (strcmp (p, "assumes") == 0)
{
c_parser_consume_token (parser);
c_parser_omp_assumption_clauses (parser, false);
@@ -22451,7 +22487,7 @@ c_parser_omp_begin (c_parser *parser)
}
else
{
- c_parser_error (parser, "expected %<assumes%>");
+ c_parser_error (parser, "expected %<declare target%> or %<assumes%>");
c_parser_skip_to_pragma_eol (parser);
}
}
@@ -22484,19 +22520,20 @@ c_parser_omp_end (c_parser *parser)
return;
}
c_parser_skip_to_pragma_eol (parser);
- if (!current_omp_declare_target_attribute)
+ if (!vec_safe_length (current_omp_declare_target_attribute))
error_at (loc, "%<#pragma omp end declare target%> without "
- "corresponding %<#pragma omp declare target%>");
+ "corresponding %<#pragma omp declare target%> or "
+ "%<#pragma omp begin declare target%>");
else
- current_omp_declare_target_attribute--;
+ current_omp_declare_target_attribute->pop ();
}
else if (strcmp (p, "assumes") == 0)
{
c_parser_consume_token (parser);
c_parser_skip_to_pragma_eol (parser);
if (!current_omp_begin_assumes)
- error_at (loc, "%<#pragma omp end assumes%> without "
- "corresponding %<#pragma omp begin assumes%>");
+ error_at (loc, "%qs without corresponding %qs",
+ "#pragma omp end assumes", "#pragma omp begin assumes");
else
current_omp_begin_assumes--;
}
@@ -153,9 +153,9 @@ static int warn_about_return_type;
static bool undef_nested_function;
-/* If non-zero, implicit "omp declare target" attribute is added into the
- attribute lists. */
-int current_omp_declare_target_attribute;
+/* Vector of implicit "omp declare target" attributes to be added into
+ the attribute lists. */
+vec<c_omp_declare_target_attr, va_gc> *current_omp_declare_target_attribute;
/* If non-zero, we are inside of
#pragma omp begin assumes ... #pragma omp end assumes region. */
@@ -5105,7 +5105,7 @@ static tree
c_decl_attributes (tree *node, tree attributes, int flags)
{
/* Add implicit "omp declare target" attribute if requested. */
- if (current_omp_declare_target_attribute
+ if (vec_safe_length (current_omp_declare_target_attribute)
&& ((VAR_P (*node) && is_global_var (*node))
|| TREE_CODE (*node) == FUNCTION_DECL))
{
@@ -5119,6 +5119,22 @@ c_decl_attributes (tree *node, tree attr
attributes = tree_cons (get_identifier ("omp declare target block"),
NULL_TREE, attributes);
}
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ {
+ int device_type
+ = current_omp_declare_target_attribute->last ().device_type;
+ device_type = MAX (device_type, 0);
+ if ((device_type & OMP_CLAUSE_DEVICE_TYPE_HOST) != 0
+ && !lookup_attribute ("omp declare target host", attributes))
+ attributes
+ = tree_cons (get_identifier ("omp declare target host"),
+ NULL_TREE, attributes);
+ if ((device_type & OMP_CLAUSE_DEVICE_TYPE_NOHOST) != 0
+ && !lookup_attribute ("omp declare target nohost", attributes))
+ attributes
+ = tree_cons (get_identifier ("omp declare target nohost"),
+ NULL_TREE, attributes);
+ }
}
/* Look up the current declaration with all the attributes merged
@@ -1855,11 +1855,12 @@ union GTY((desc ("cp_tree_node_structure
};
-struct GTY(()) omp_declare_target_attr {
+struct GTY(()) cp_omp_declare_target_attr {
bool attr_syntax;
+ int device_type;
};
-struct GTY(()) omp_begin_assumes_data {
+struct GTY(()) cp_omp_begin_assumes_data {
bool attr_syntax;
};
@@ -1909,8 +1910,8 @@ struct GTY(()) saved_scope {
cp_binding_level *bindings;
hash_map<tree, tree> *GTY((skip)) x_local_specializations;
- vec<omp_declare_target_attr, va_gc> *omp_declare_target_attribute;
- vec<omp_begin_assumes_data, va_gc> *omp_begin_assumes;
+ vec<cp_omp_declare_target_attr, va_gc> *omp_declare_target_attribute;
+ vec<cp_omp_begin_assumes_data, va_gc> *omp_begin_assumes;
struct saved_scope *prev;
};
@@ -40315,8 +40315,8 @@ cp_parser_omp_clause_device_type (cp_par
goto resync_fail;
c = build_omp_clause (location, OMP_CLAUSE_DEVICE_TYPE);
- /* check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE_TYPE, "device_type",
- location); */
+ check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE_TYPE, "device_type",
+ location);
OMP_CLAUSE_DEVICE_TYPE_KIND (c) = kind;
OMP_CLAUSE_CHAIN (c) = list;
return c;
@@ -40840,7 +40840,7 @@ cp_parser_omp_all_clauses (cp_parser *pa
break;
case PRAGMA_OMP_CLAUSE_LINK:
clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_LINK, clauses);
- c_name = "to";
+ c_name = "link";
break;
case PRAGMA_OMP_CLAUSE_TO:
if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)) != 0)
@@ -46737,8 +46737,8 @@ cp_parser_omp_declare_target (cp_parser
}
else
{
- struct omp_declare_target_attr a
- = { parser->lexer->in_omp_attribute_pragma };
+ cp_omp_declare_target_attr a
+ = { parser->lexer->in_omp_attribute_pragma, -1 };
vec_safe_push (scope_chain->omp_declare_target_attribute, a);
cp_parser_require_pragma_eol (parser, pragma_tok);
return;
@@ -46763,12 +46763,17 @@ cp_parser_omp_declare_target (cp_parser
device_type);
}
if (device_type && only_device_type)
- warning_at (OMP_CLAUSE_LOCATION (clauses), 0,
- "directive with only %<device_type%> clauses ignored");
+ error_at (OMP_CLAUSE_LOCATION (clauses),
+ "directive with only %<device_type%> clause");
}
/* OpenMP 5.1
- #pragma omp begin assumes clauses[optseq] new-line */
+ # pragma omp begin assumes clauses[optseq] new-line
+
+ # pragma omp begin declare target clauses[optseq] new-line */
+
+#define OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK \
+ (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE)
static void
cp_parser_omp_begin (cp_parser *parser, cp_token *pragma_tok)
@@ -46780,16 +46785,47 @@ cp_parser_omp_begin (cp_parser *parser,
tree id = cp_lexer_peek_token (parser->lexer)->u.value;
p = IDENTIFIER_POINTER (id);
}
- if (strcmp (p, "assumes") == 0)
+ if (strcmp (p, "declare") == 0)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ p = "";
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ p = IDENTIFIER_POINTER (id);
+ }
+ if (strcmp (p, "target") == 0)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ tree clauses
+ = cp_parser_omp_all_clauses (parser,
+ OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK,
+ "#pragma omp begin declare target",
+ pragma_tok);
+ int device_type = 0;
+ for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE)
+ device_type |= OMP_CLAUSE_DEVICE_TYPE_KIND (c);
+ cp_omp_declare_target_attr a
+ = { in_omp_attribute_pragma, device_type };
+ vec_safe_push (scope_chain->omp_declare_target_attribute, a);
+ }
+ else
+ {
+ cp_parser_error (parser, "expected %<target%>");
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ }
+ }
+ else if (strcmp (p, "assumes") == 0)
{
cp_lexer_consume_token (parser->lexer);
cp_parser_omp_assumption_clauses (parser, pragma_tok, false);
- struct omp_begin_assumes_data a = { in_omp_attribute_pragma };
+ cp_omp_begin_assumes_data a = { in_omp_attribute_pragma };
vec_safe_push (scope_chain->omp_begin_assumes, a);
}
else
{
- cp_parser_error (parser, "expected %<assumes%>");
+ cp_parser_error (parser, "expected %<declare target%> or %<assumes%>");
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
}
}
@@ -46831,21 +46867,28 @@ cp_parser_omp_end (cp_parser *parser, cp
if (!vec_safe_length (scope_chain->omp_declare_target_attribute))
error_at (pragma_tok->location,
"%<#pragma omp end declare target%> without corresponding "
- "%<#pragma omp declare target%>");
+ "%<#pragma omp declare target%> or "
+ "%<#pragma omp begin declare target%>");
else
{
- omp_declare_target_attr
+ cp_omp_declare_target_attr
a = scope_chain->omp_declare_target_attribute->pop ();
if (a.attr_syntax != in_omp_attribute_pragma)
{
if (a.attr_syntax)
error_at (pragma_tok->location,
- "%<declare target%> in attribute syntax terminated "
- "with %<end declare target%> in pragma syntax");
+ "%qs in attribute syntax terminated "
+ "with %qs in pragma syntax",
+ a.device_type >= 0 ? "begin declare target"
+ : "declare target",
+ "end declare target");
else
error_at (pragma_tok->location,
- "%<declare target%> in pragma syntax terminated "
- "with %<end declare target%> in attribute syntax");
+ "%qs in pragma syntax terminated "
+ "with %qs in attribute syntax",
+ a.device_type >= 0 ? "begin declare target"
+ : "declare target",
+ "end declare target");
}
}
}
@@ -46855,22 +46898,24 @@ cp_parser_omp_end (cp_parser *parser, cp
cp_parser_require_pragma_eol (parser, pragma_tok);
if (!vec_safe_length (scope_chain->omp_begin_assumes))
error_at (pragma_tok->location,
- "%<#pragma omp end assumes%> without corresponding "
- "%<#pragma omp begin assumes%>");
+ "%qs without corresponding %qs",
+ "#pragma omp end assumes", "#pragma omp begin assumes");
else
{
- omp_begin_assumes_data
+ cp_omp_begin_assumes_data
a = scope_chain->omp_begin_assumes->pop ();
if (a.attr_syntax != in_omp_attribute_pragma)
{
if (a.attr_syntax)
error_at (pragma_tok->location,
- "%<begin assumes%> in attribute syntax terminated "
- "with %<end assumes%> in pragma syntax");
+ "%qs in attribute syntax terminated "
+ "with %qs in pragma syntax",
+ "begin assumes", "end assumes");
else
error_at (pragma_tok->location,
- "%<begin assumes%> in pragma syntax terminated "
- "with %<end assumes%> in attribute syntax");
+ "%qs in pragma syntax terminated "
+ "with %qs in attribute syntax",
+ "begin assumes", "end assumes");
}
}
}
@@ -3358,16 +3358,20 @@ finish_translation_unit (void)
if (vec_safe_length (scope_chain->omp_declare_target_attribute))
{
+ cp_omp_declare_target_attr
+ a = scope_chain->omp_declare_target_attribute->pop ();
if (!errorcount)
- error ("%<#pragma omp declare target%> without corresponding "
- "%<#pragma omp end declare target%>");
+ error ("%qs without corresponding %qs",
+ a.device_type >= 0 ? "#pragma omp begin declare target"
+ : "#pragma omp declare target",
+ "#pragma omp end declare target");
vec_safe_truncate (scope_chain->omp_declare_target_attribute, 0);
}
if (vec_safe_length (scope_chain->omp_begin_assumes))
{
if (!errorcount)
- error ("%<#pragma omp begin assumes%> without corresponding "
- "%<#pragma omp end assumes%>");
+ error ("%qs without corresponding %qs",
+ "#pragma omp begin assumes", "#pragma omp end assumes");
vec_safe_truncate (scope_chain->omp_begin_assumes, 0);
}
}
@@ -1652,17 +1652,40 @@ cplus_decl_attributes (tree *decl, tree
&& DECL_CLASS_SCOPE_P (*decl))
error ("%q+D static data member inside of declare target directive",
*decl);
- else if (VAR_P (*decl)
- && (processing_template_decl
- || !omp_mappable_type (TREE_TYPE (*decl))))
- attributes = tree_cons (get_identifier ("omp declare target implicit"),
- NULL_TREE, attributes);
else
{
- attributes = tree_cons (get_identifier ("omp declare target"),
- NULL_TREE, attributes);
- attributes = tree_cons (get_identifier ("omp declare target block"),
- NULL_TREE, attributes);
+ if (VAR_P (*decl)
+ && (processing_template_decl
+ || !omp_mappable_type (TREE_TYPE (*decl))))
+ attributes
+ = tree_cons (get_identifier ("omp declare target implicit"),
+ NULL_TREE, attributes);
+ else
+ {
+ attributes = tree_cons (get_identifier ("omp declare target"),
+ NULL_TREE, attributes);
+ attributes
+ = tree_cons (get_identifier ("omp declare target block"),
+ NULL_TREE, attributes);
+ }
+ if (TREE_CODE (*decl) == FUNCTION_DECL)
+ {
+ cp_omp_declare_target_attr &last
+ = scope_chain->omp_declare_target_attribute->last ();
+ int device_type = MAX (last.device_type, 0);
+ if ((device_type & OMP_CLAUSE_DEVICE_TYPE_HOST) != 0
+ && !lookup_attribute ("omp declare target host",
+ attributes))
+ attributes
+ = tree_cons (get_identifier ("omp declare target host"),
+ NULL_TREE, attributes);
+ if ((device_type & OMP_CLAUSE_DEVICE_TYPE_NOHOST) != 0
+ && !lookup_attribute ("omp declare target nohost",
+ attributes))
+ attributes
+ = tree_cons (get_identifier ("omp declare target nohost"),
+ NULL_TREE, attributes);
+ }
}
}
@@ -1,8 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fopenmp" } */
-#pragma omp declare target device_type (any) /* { dg-warning "directive with only 'device_type' clauses ignored" } */
-
void f1 (void) {}
void f2 (void);
#pragma omp declare target to (f1) device_type (any) to (f2)
@@ -38,7 +36,3 @@ void f13 (void) {}
void f14 (void) {}
#pragma omp declare target device_type (nohost) to (f14)
#pragma omp declare target device_type (any) to (f14)
-void f15 (void) {}
-#pragma omp declare target device_type (host) to (f15) device_type (nohost)
-void f16 (void) {}
-#pragma omp declare target device_type (any) to (f15) device_type (any)
@@ -1,2 +1,2 @@
-#pragma omp end declare target /* { dg-error "'#pragma omp end declare target' without corresponding '#pragma omp declare target'" } */
+#pragma omp end declare target /* { dg-error "'#pragma omp end declare target' without corresponding '#pragma omp declare target' or '#pragma omp begin declare target'" } */
void foo (void);
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+#pragma omp declare target device_type (any) /* { dg-error "directive with only 'device_type' clause" } */
+
+void f1 (void) {}
+#pragma omp declare target device_type (host) to (f1) device_type (nohost) /* { dg-error "too many 'device_type' clauses" } */
+#pragma omp declare target device_type (any) to (f1) device_type (any) /* { dg-error "too many 'device_type' clauses" } */
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+extern int a;
+#pragma omp begin declare target device_type (host)
+int b;
+#pragma omp begin declare target device_type (any)
+char d;
+#pragma omp end declare target
+#pragma omp end declare target
+#pragma omp begin declare target
+long c;
+#pragma omp end declare target
+#pragma omp declare target
+int foo (void) { return 0; }
+#pragma omp begin declare target device_type (any)
+int bar (void) { return 0; }
+#pragma omp end declare target
+#pragma omp end declare target
+#pragma omp begin declare target device_type (any)
+int baz (void) { return 0; }
+#pragma omp declare target
+int qux (void) { return 0; }
+#pragma omp end declare target
+#pragma omp end declare target
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+extern int a;
+#pragma omp begin declare target
+#pragma omp declare target to (a)
+#pragma omp end declare target
+int b;
+#pragma omp begin declare target to (b) /* { dg-error "'to' is not valid for '#pragma omp begin declare target'" } */
+#pragma omp end declare target
+int c;
+#pragma omp begin declare target link (c) /* { dg-error "'link' is not valid for '#pragma omp begin declare target'" } */
+#pragma omp end declare target
+int m;
+#pragma omp begin declare target device_type (host) device_type (any) /* { dg-error "too many 'device_type' clauses" } */
+#pragma omp end declare target
+#pragma omp begin declare target
+#pragma omp end declare target to (p) /* { dg-error "expected end of line before .to." } */
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+#pragma omp begin declare target
+int a[] = { 1, 2, 3 };
+extern int b[]; /* { dg-error "'b' in declare target directive does not have mappable type" } */
+extern int c[]; /* { dg-error "'c' in declare target directive does not have mappable type" } */
+extern int d[]; /* { dg-error "'d' in declare target directive does not have mappable type" } */
+int d[3];
+#pragma omp end declare target
+int c[3];
+#pragma omp begin declare target device_type (host)
+int e[] = { 1, 2, 3 };
+extern int f[]; /* { dg-error "'f' in declare target directive does not have mappable type" } */
+extern int g[]; /* { dg-error "'g' in declare target directive does not have mappable type" } */
+extern int h[]; /* { dg-error "'h' in declare target directive does not have mappable type" } */
+int h[3];
+#pragma omp end declare target
+int g[3];
@@ -0,0 +1,2 @@
+#pragma omp begin declare target
+void foo (void); /* { dg-error "'#pragma omp begin declare target' without corresponding '#pragma omp end declare target'" } */
@@ -14,6 +14,21 @@ int b, c, e;
int d;
[[omp::directive (end declare target)]];
[[omp::directive (end declare target)]];
+[[omp::directive (begin declare target, device_type (any))]];
+[[omp::directive (begin declare target)]];
+int f;
+[[omp::directive (end declare target)]];
+[[omp::directive (end declare target)]];
+[[omp::directive (begin declare target device_type (host))]];
+[[omp::directive (declare target)]];
+int g;
+[[omp::directive (end declare target)]];
+[[omp::directive (end declare target)]];
+[[omp::directive (declare target)]];
+[[omp::directive (begin declare target, device_type (nohost))]];
+int h;
+[[omp::directive (end declare target)]];
+[[omp::directive (end declare target)]];
[[omp::directive (nothing)]];
[[omp::directive (begin assumes no_openmp no_openmp_routines no_parallelism
absent (atomic, barrier, cancel, cancellation point)
@@ -0,0 +1,41 @@
+// { dg-do compile { target c++11 } }
+
+#pragma omp begin declare target
+#pragma omp begin declare target device_type (any)
+[[omp::directive (begin declare target, device_type (host))]];
+int a;
+[[omp::directive (end declare target)]];
+#pragma omp end declare target
+#pragma omp end declare target
+[[omp::directive (begin declare target device_type (nohost))]];
+int b;
+#pragma omp end declare target // { dg-error "'begin declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" }
+#pragma omp begin declare target
+int c;
+[[omp::directive (end declare target)]];// { dg-error "'begin declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" }
+#pragma omp begin declare target device_type (host)
+[[omp::directive (begin declare target)]];
+int d;
+#pragma omp end declare target // { dg-error "'begin declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" }
+#pragma omp begin declare target
+int e;
+[[omp::directive (end declare target)]];// { dg-error "'begin declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" }
+#pragma omp end declare target
+[[omp::directive (begin declare target device_type (any))]];
+[[omp::directive (begin declare target)]];
+int f;
+#pragma omp end declare target // { dg-error "'begin declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" }
+#pragma omp begin declare target
+int g;
+[[omp::directive (end declare target)]];// { dg-error "'begin declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" }
+[[omp::directive (end declare target)]];
+[[omp::directive (begin declare target)]];
+#pragma omp begin declare target
+int h;
+#pragma omp end declare target
+#pragma omp end declare target // { dg-error "'begin declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" }
+#pragma omp begin declare target
+[[omp::directive (begin declare target)]];
+int i;
+[[omp::directive (end declare target)]];
+[[omp::directive (end declare target)]];// { dg-error "'begin declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" }
@@ -345,7 +345,7 @@ The OpenMP 4.5 specification is fully su
@item Support of structured block sequences in C/C++ @tab Y @tab
@item @code{unconstrained} and @code{reproducible} modifiers on @code{order}
clause @tab Y @tab
-@item Support @code{begin/end declare target} syntax in C/C++ @tab N @tab
+@item Support @code{begin/end declare target} syntax in C/C++ @tab Y @tab
@item Pointer predetermined firstprivate getting initialized
to address of matching mapped list item per 5.1, Sect. 2.21.7.2 @tab N @tab
@item For Fortran, diagnose placing declarative before/between @code{USE},