From: Julian Brown Date: Tue, 12 Feb 2019 22:56:12 +0000 (-0800) Subject: Various OpenACC reduction enhancements - FE changes X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5553bdf38289d2c5a1af471a88f639edead9a19d;p=thirdparty%2Fgcc.git Various OpenACC reduction enhancements - FE changes This version differs somewhat from the last version posted upstream (and addresses some of Jakub's review comments). 2018-12-13 Cesar Philippidis Nathan Sidwell Julian Brown gcc/c/ * c-parser.cc (c_parser_omp_variable_list): New c_omp_region_type argument. Use it to specialize handling of OMP_CLAUSE_REDUCTION for OpenACC. (c_parser_oacc_data_clause): Add region-type argument. (c_parser_oacc_data_clause_deviceptr): Likewise. (c_parser_omp_clause_reduction): Change is_omp boolean parameter to c_omp_region_type. Update call to c_parser_omp_variable_list. (c_parser_oacc_all_clauses): Update calls to c_parser_omp_clause_reduction. (c_parser_omp_all_clauses): Likewise. (c_parser_oacc_cache): Update call to c_parser_omp_var_list_parens. * c-typeck.cc (c_finish_omp_clauses): Emit an error on orphan OpenACC gang reductions. Suppress user-defined reduction error for OpenACC. gcc/cp/ * parser.cc (cp_parser_omp_var_list_no_open): New c_omp_region_type argument. Use it to specialize handling of OMP_CLAUSE_REDUCTION for OpenACC. (cp_parser_omp_var_list): Add c_omp_region_type argument. Update call to cp_parser_omp_var_list_parens. (cp_parser_oacc_data_clause): Update call to cp_parser_omp_var_list. (cp_parser_omp_clause_reduction): Change is_omp boolean parameter to c_omp_region_type. Update call to cp_parser_omp_var_list_no_open. (cp_parser_oacc_all_clauses): Update call to cp_parser_omp_clause_reduction. (cp_parser_omp_all_clauses): Likewise. * semantics.cc (finish_omp_reduction_clause): Add c_omp_region_type argument. Suppress user-defined reduction error for OpenACC. (finish_omp_clauses): Emit an error on orphan OpenACC gang reductions. gcc/fortran/ * openmp.cc (oacc_is_parallel): New. (resolve_oacc_loop_blocks): Emit an error on orphan OpenACC gang reductions. * trans-openmp.cc (gfc_omp_clause_copy_ctor): Permit reductions. 2022-02-03 Kwok Cheung Yeung gcc/c/ * c-parser.cc (c_parser_omp_clause_map): Update call to c_parser_omp_variable_list. (c_parser_omp_clause_to): Update call to c_parser_omp_var_list_parens. (c_parser_omp_clause_from): Likewise. gcc/cp/ * parser.cc (cp_parser_omp_clause_map): Update call to cp_parser_omp_var_list_no_open. (cp_parser_omp_all_clauses): Update calls to cp_parser_omp_var_list. --- diff --git a/gcc/c/ChangeLog.omp b/gcc/c/ChangeLog.omp index 76ed3228d5dd..a95b2adc8f84 100644 --- a/gcc/c/ChangeLog.omp +++ b/gcc/c/ChangeLog.omp @@ -1,3 +1,28 @@ +2022-02-03 Kwok Cheung Yeung + + * c-parser.ccc (c_parser_omp_clause_map): Update call to + c_parser_omp_variable_list. + (c_parser_omp_clause_to): Update call to c_parser_omp_var_list_parens. + (c_parser_omp_clause_from): Likewise. + +2018-12-13 Cesar Philippidis + Nathan Sidwell + Julian Brown + + * c-parser.c (c_parser_omp_variable_list): New c_omp_region_type + argument. Use it to specialize handling of OMP_CLAUSE_REDUCTION for + OpenACC. + (c_parser_oacc_data_clause): Add region-type argument. + (c_parser_oacc_data_clause_deviceptr): Likewise. + (c_parser_omp_clause_reduction): Change is_omp boolean parameter to + c_omp_region_type. Update call to c_parser_omp_variable_list. + (c_parser_oacc_all_clauses): Update calls to + c_parser_omp_clause_reduction. + (c_parser_omp_all_clauses): Likewise. + (c_parser_oacc_cache): Update call to c_parser_omp_var_list_parens. + * c-typeck.c (c_finish_omp_clauses): Emit an error on orphan OpenACC + gang reductions. Suppress user-defined reduction error for OpenACC. + 2020-04-19 Chung-Lin Tang PR other/76739 diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 21bc3167ce22..21416a8dc3d3 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -13718,6 +13718,7 @@ static tree c_parser_omp_variable_list (c_parser *parser, location_t clause_loc, enum omp_clause_code kind, tree list, + enum c_omp_region_type ort = C_ORT_OMP, bool allow_deref = false) { auto_vec dims; @@ -13902,7 +13903,8 @@ c_parser_omp_variable_list (c_parser *parser, case OMP_CLAUSE_HAS_DEVICE_ADDR: array_section_p = false; dims.truncate (0); - while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) + while ((ort != C_ORT_ACC || kind != OMP_CLAUSE_REDUCTION) + && c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) { location_t loc = UNKNOWN_LOCATION; tree low_bound = NULL_TREE, length = NULL_TREE; @@ -14040,7 +14042,9 @@ c_parser_omp_variable_list (c_parser *parser, static tree c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, - tree list, bool allow_deref = false) + tree list, + enum c_omp_region_type ort = C_ORT_OMP, + bool allow_deref = false) { /* The clauses location. */ location_t loc = c_parser_peek_token (parser)->location; @@ -14048,7 +14052,8 @@ c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, matching_parens parens; if (parens.require_open (parser)) { - list = c_parser_omp_variable_list (parser, loc, kind, list, allow_deref); + list = c_parser_omp_variable_list (parser, loc, kind, list, ort, + allow_deref); parens.skip_until_found_close (parser); } return list; @@ -14117,7 +14122,8 @@ c_parser_oacc_data_clause (c_parser *parser, pragma_omp_clause c_kind, gcc_unreachable (); } tree nl, c; - nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_MAP, list, true); + nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_MAP, list, C_ORT_ACC, + true); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_SET_MAP_KIND (c, kind); @@ -14137,7 +14143,8 @@ c_parser_oacc_data_clause_deviceptr (c_parser *parser, tree list) /* Can't use OMP_CLAUSE_MAP here (that is, can't use the generic c_parser_oacc_data_clause), as for PRAGMA_OACC_CLAUSE_DEVICEPTR, variable-list must only allow for pointer variables. */ - vars = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL); + vars = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL, + C_ORT_ACC); for (t = vars; t && t; t = TREE_CHAIN (t)) { tree v = TREE_PURPOSE (t); @@ -15604,7 +15611,7 @@ c_parser_omp_clause_private (c_parser *parser, tree list) static tree c_parser_omp_clause_reduction (c_parser *parser, enum omp_clause_code kind, - bool is_omp, tree list) + enum c_omp_region_type ort, tree list) { location_t clause_loc = c_parser_peek_token (parser)->location; matching_parens parens; @@ -15615,7 +15622,7 @@ c_parser_omp_clause_reduction (c_parser *parser, enum omp_clause_code kind, enum tree_code code = ERROR_MARK; tree reduc_id = NULL_TREE; - if (kind == OMP_CLAUSE_REDUCTION && is_omp) + if (kind == OMP_CLAUSE_REDUCTION && ort == C_ORT_OMP) { if (c_parser_next_token_is_keyword (parser, RID_DEFAULT) && c_parser_peek_2nd_token (parser)->type == CPP_COMMA) @@ -15696,7 +15703,8 @@ c_parser_omp_clause_reduction (c_parser *parser, enum omp_clause_code kind, { tree nl, c; - nl = c_parser_omp_variable_list (parser, clause_loc, kind, list); + nl = c_parser_omp_variable_list (parser, clause_loc, kind, list, ort); + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) { tree d = OMP_CLAUSE_DECL (c), type; @@ -17173,7 +17181,7 @@ c_parser_omp_clause_map (c_parser *parser, tree list) } nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_MAP, list, - true); + C_ORT_OMP, true); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_SET_MAP_KIND (c, kind); @@ -17417,7 +17425,8 @@ c_parser_omp_clause_device_type (c_parser *parser, tree list) static tree c_parser_omp_clause_to (c_parser *parser, tree list) { - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list, true); + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list, + C_ORT_OMP, true); } /* OpenMP 4.0: @@ -17426,7 +17435,8 @@ c_parser_omp_clause_to (c_parser *parser, tree list) static tree c_parser_omp_clause_from (c_parser *parser, tree list) { - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list, true); + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list, + C_ORT_OMP, true); } /* OpenMP 4.0: @@ -17648,7 +17658,7 @@ c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask, case PRAGMA_OACC_CLAUSE_REDUCTION: clauses = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_REDUCTION, - false, clauses); + C_ORT_ACC, clauses); c_name = "reduction"; break; case PRAGMA_OACC_CLAUSE_SEQ: @@ -17804,7 +17814,7 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, case PRAGMA_OMP_CLAUSE_IN_REDUCTION: clauses = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_IN_REDUCTION, - true, clauses); + C_ORT_OMP, clauses); c_name = "in_reduction"; break; case PRAGMA_OMP_CLAUSE_LASTPRIVATE: @@ -17846,7 +17856,7 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, case PRAGMA_OMP_CLAUSE_REDUCTION: clauses = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_REDUCTION, - true, clauses); + C_ORT_OMP, clauses); c_name = "reduction"; break; case PRAGMA_OMP_CLAUSE_SCHEDULE: @@ -17860,7 +17870,7 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, case PRAGMA_OMP_CLAUSE_TASK_REDUCTION: clauses = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_TASK_REDUCTION, - true, clauses); + C_ORT_OMP, clauses); c_name = "task_reduction"; break; case PRAGMA_OMP_CLAUSE_UNTIED: @@ -18099,7 +18109,8 @@ c_parser_oacc_cache (location_t loc, c_parser *parser) { tree stmt, clauses; - clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE__CACHE_, NULL); + clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE__CACHE_, NULL, + C_ORT_ACC); clauses = c_finish_omp_clauses (clauses, C_ORT_ACC); c_parser_skip_to_pragma_eol (parser); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 0f30d96b46ca..8bf20e702326 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -14799,8 +14799,11 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == error_mark_node) { - error_at (OMP_CLAUSE_LOCATION (c), - "user defined reduction not found for %qE", t); + /* There are no user-defined reductions in OpenACC (as of + 2.6). */ + if (ort & C_ORT_OMP) + error_at (OMP_CLAUSE_LOCATION (c), + "user defined reduction not found for %qE", t); remove = true; break; } diff --git a/gcc/cp/ChangeLog.omp b/gcc/cp/ChangeLog.omp index 624388c45cc7..a87d118e4bb2 100644 --- a/gcc/cp/ChangeLog.omp +++ b/gcc/cp/ChangeLog.omp @@ -1,3 +1,28 @@ +2022-02-03 Kwok Cheung Yeung + + * parser.ccc (cp_parser_omp_clause_map): Update call to + cp_parser_omp_var_list_no_open. + (cp_parser_omp_all_clauses): Update calls to cp_parser_omp_var_list. + +2018-12-13 Cesar Philippidis + Nathan Sidwell + Julian Brown + + * parser.c (cp_parser_omp_var_list_no_open): New c_omp_region_type + argument. Use it to specialize handling of OMP_CLAUSE_REDUCTION for + OpenACC. + (cp_parser_omp_var_list): Add c_omp_region_type argument. Update call + to cp_parser_omp_var_list_parens. + (cp_parser_oacc_data_clause): Update call to cp_parser_omp_var_list. + (cp_parser_omp_clause_reduction): Change is_omp boolean parameter to + c_omp_region_type. Update call to cp_parser_omp_var_list_no_open. + (cp_parser_oacc_all_clauses): Update call to + cp_parser_omp_clause_reduction. + (cp_parser_omp_all_clauses): Likewise. + * semantics.c (finish_omp_reduction_clause): Add c_omp_region_type + argument. Suppress user-defined reduction error for OpenACC. + (finish_omp_clauses): Emit an error on orphan OpenACC gang reductions. + 2020-04-19 Chung-Lin Tang PR other/76739 diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index a6341b98af21..199db43f19cb 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -37416,6 +37416,7 @@ struct omp_dim static tree cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, tree list, bool *colon, + enum c_omp_region_type ort = C_ORT_OMP, bool allow_deref = false) { auto_vec dims; @@ -37535,7 +37536,8 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, case OMP_CLAUSE_HAS_DEVICE_ADDR: array_section_p = false; dims.truncate (0); - while (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE)) + while ((ort != C_ORT_ACC || kind != OMP_CLAUSE_REDUCTION) + && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE)) { location_t loc = UNKNOWN_LOCATION; tree low_bound = NULL_TREE, length = NULL_TREE; @@ -37683,10 +37685,11 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, static tree cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list, + enum c_omp_region_type ort = C_ORT_OMP, bool allow_deref = false) { if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) - return cp_parser_omp_var_list_no_open (parser, kind, list, NULL, + return cp_parser_omp_var_list_no_open (parser, kind, list, NULL, ort, allow_deref); return list; } @@ -37754,7 +37757,7 @@ cp_parser_oacc_data_clause (cp_parser *parser, pragma_omp_clause c_kind, gcc_unreachable (); } tree nl, c; - nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_MAP, list, true); + nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_MAP, list, C_ORT_ACC, true); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_SET_MAP_KIND (c, kind); @@ -39046,7 +39049,7 @@ cp_parser_omp_clause_ordered (cp_parser *parser, static tree cp_parser_omp_clause_reduction (cp_parser *parser, enum omp_clause_code kind, - bool is_omp, tree list) + enum c_omp_region_type ort, tree list) { enum tree_code code = ERROR_MARK; tree nlist, c, id = NULL_TREE; @@ -39056,7 +39059,7 @@ cp_parser_omp_clause_reduction (cp_parser *parser, enum omp_clause_code kind, if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return list; - if (kind == OMP_CLAUSE_REDUCTION && is_omp) + if (kind == OMP_CLAUSE_REDUCTION && ort == C_ORT_OMP) { if (cp_lexer_next_token_is_keyword (parser->lexer, RID_DEFAULT) && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COMMA)) @@ -39153,8 +39156,7 @@ cp_parser_omp_clause_reduction (cp_parser *parser, enum omp_clause_code kind, if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) goto resync_fail; - nlist = cp_parser_omp_var_list_no_open (parser, kind, list, - NULL); + nlist = cp_parser_omp_var_list_no_open (parser, kind, list, NULL, ort); for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) { OMP_CLAUSE_REDUCTION_CODE (c) = code; @@ -40579,7 +40581,7 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) } nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_MAP, list, - NULL, true); + NULL, C_ORT_OMP, true); for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_SET_MAP_KIND (c, kind); @@ -41007,7 +41009,7 @@ cp_parser_oacc_all_clauses (cp_parser *parser, omp_clause_mask mask, case PRAGMA_OACC_CLAUSE_REDUCTION: clauses = cp_parser_omp_clause_reduction (parser, OMP_CLAUSE_REDUCTION, - false, clauses); + C_ORT_ACC, clauses); c_name = "reduction"; break; case PRAGMA_OACC_CLAUSE_SEQ: @@ -41195,7 +41197,7 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, case PRAGMA_OMP_CLAUSE_IN_REDUCTION: clauses = cp_parser_omp_clause_reduction (parser, OMP_CLAUSE_IN_REDUCTION, - true, clauses); + C_ORT_OMP, clauses); c_name = "in_reduction"; break; case PRAGMA_OMP_CLAUSE_LASTPRIVATE: @@ -41245,7 +41247,7 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, case PRAGMA_OMP_CLAUSE_REDUCTION: clauses = cp_parser_omp_clause_reduction (parser, OMP_CLAUSE_REDUCTION, - true, clauses); + C_ORT_OMP, clauses); c_name = "reduction"; break; case PRAGMA_OMP_CLAUSE_SCHEDULE: @@ -41262,7 +41264,7 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, clauses = cp_parser_omp_clause_reduction (parser, OMP_CLAUSE_TASK_REDUCTION, - true, clauses); + C_ORT_OMP, clauses); c_name = "task_reduction"; break; case PRAGMA_OMP_CLAUSE_UNTIED: @@ -41334,12 +41336,12 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, } else clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO, clauses, - true); + C_ORT_OMP, true); c_name = "to"; break; case PRAGMA_OMP_CLAUSE_FROM: clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM, clauses, - true); + C_ORT_OMP, true); c_name = "from"; break; case PRAGMA_OMP_CLAUSE_UNIFORM: diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 0bb608d95b2b..e7d622956095 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -6261,7 +6261,8 @@ find_omp_placeholder_r (tree *tp, int *, void *data) Return true if there is some error and the clause should be removed. */ static bool -finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) +finish_omp_reduction_clause (tree c, enum c_omp_region_type ort, + bool *need_default_ctor, bool *need_dtor) { tree t = OMP_CLAUSE_DECL (c); bool predefined = false; @@ -6507,9 +6508,11 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) *need_dtor = true; else { - error_at (OMP_CLAUSE_LOCATION (c), - "user defined reduction not found for %qE", - omp_clause_printable_decl (t)); + /* There are no user-defined reductions for OpenACC (as of 2.6). */ + if (ort & C_ORT_OMP) + error_at (OMP_CLAUSE_LOCATION (c), + "user defined reduction not found for %qE", + omp_clause_printable_decl (t)); return true; } if (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF) @@ -6824,7 +6827,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (ort & C_ORT_ACC) for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ASYNC) - { + { oacc_async = true; break; } @@ -9088,7 +9091,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (processing_template_decl && !VAR_P (t) && TREE_CODE (t) != PARM_DECL) break; - if (finish_omp_reduction_clause (c, &need_default_ctor, + if (finish_omp_reduction_clause (c, ort, &need_default_ctor, &need_dtor)) remove = true; else diff --git a/gcc/fortran/ChangeLog.omp b/gcc/fortran/ChangeLog.omp index 379b2aee1498..23e93c873232 100644 --- a/gcc/fortran/ChangeLog.omp +++ b/gcc/fortran/ChangeLog.omp @@ -1,3 +1,12 @@ +2018-12-13 Cesar Philippidis + Nathan Sidwell + Julian Brown + + * openmp.cc (oacc_is_parallel): New. + (resolve_oacc_loop_blocks): Emit an error on orphan OpenACC + gang reductions. + * trans-openmp.ccc (gfc_omp_clause_copy_ctor): Permit reductions. + 2018-06-29 Cesar Philippidis James Norris diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc index b31cb5a9ef6f..2439aba3ca1c 100644 --- a/gcc/fortran/trans-openmp.cc +++ b/gcc/fortran/trans-openmp.cc @@ -848,7 +848,8 @@ gfc_omp_clause_copy_ctor (tree clause, tree dest, tree src) stmtblock_t block, cond_block; gcc_assert (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_FIRSTPRIVATE - || OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_LINEAR); + || OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_LINEAR + || OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_REDUCTION); /* Privatize pointer, only; cf. gfc_omp_predetermined_sharing. */ if (DECL_P (OMP_CLAUSE_DECL (clause))