From patchwork Wed Sep 20 06:48:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 142249 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:612c:172:b0:3f2:4152:657d with SMTP id h50csp3924229vqi; Tue, 19 Sep 2023 23:49:48 -0700 (PDT) X-Google-Smtp-Source: AGHT+IH6CIHoSzSuZhwT4ukHlDKrvc41GCSuDNGcRCsOd4BfxCNL3ZOyIA2Lo5KjQxnRMQDt3nbl X-Received: by 2002:a05:6512:360a:b0:503:385c:4319 with SMTP id f10-20020a056512360a00b00503385c4319mr1548360lfs.19.1695192588129; Tue, 19 Sep 2023 23:49:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1695192588; cv=none; d=google.com; s=arc-20160816; b=ZOQpKA94Tazd+UYCvccLfm7AAWTMUUMaOn14USkHjDCgomNiR9rx5/wJnrxSwLB0ia kR5H5QAVd3Ml/GccS+MiW/PFuYLAssYH7oeqfy3FcuRW8i8Q5xBojhTbOZp/7LETEptn 73UeCB2fZD/6hx7yMbfQDh+5JdRfEkSpQqoOD/EU+4gPJ2nEwErDxdO6+eK99gVewxuO E85NibT4+RmHiX6hRDAXuihImMrSaIopwNRh1vT+5drfMN16SMpfi4DFd73IvVNORduS cShBZYpYpeV00w2tj7qA3JQLz66cAnQte++dCn2bxqxWcuMbYDDn2fEE5QS+GRlA7XwS qgtA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:reply-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-disposition :mime-version:message-id:subject:cc:to:from:date:dkim-signature :dmarc-filter:delivered-to; bh=RjGSGieACwWlB0glXoB3zeH1iBSvzP84NySDGi7dQdw=; fh=zj78/O+q0guS5uROWuq0Sap/gJBgRHz16re1BmqZyHM=; b=g51samanSfVdh0udkTNSOgx54TAr+leklvDjWX6J57Kt1QKTqZWXU/Mld3KGRcbjOi Dj6LXQyEMhBJz6Des4DtJz3ormHs/7oB4nQ++Gfp/Lz+DVuUlTexJqzQwf0hRBmX7Zsw dZq8uD82EmOJHB3XFd1IqATRS8HZqU5heYlb+/weilmLsD5vvXg8PeB3fAvH+Rh1wJxY 1Nz/xoqqhNvEuMLqYYU1bOk7Mx1ZbsHiNUuh0W9Ovhoer82vtV2v6OiyID3fLXZJftqg ubbUqI3qS52H3jNHbijiOAo7+ZcwMA6uIrj7fpwy/1DW6D5qvQWltYYjUPn4SDRxrdJC SaaA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=K3q6y4k1; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id v6-20020aa7d806000000b005308d559c65si9864256edq.513.2023.09.19.23.49.47 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 19 Sep 2023 23:49:48 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=K3q6y4k1; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 167783858031 for ; Wed, 20 Sep 2023 06:49:24 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.145.221.124]) by sourceware.org (Postfix) with ESMTPS id AB6863858C62 for ; Wed, 20 Sep 2023 06:48:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org AB6863858C62 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1695192534; h=from:from:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type; bh=RjGSGieACwWlB0glXoB3zeH1iBSvzP84NySDGi7dQdw=; b=K3q6y4k1N3W93F/i9C7f70mGEHTZVnSRAnjaiw4SvycZb7LwfU3hElmhdraG2efmBPl/s5 6lEvcqWrs0xTnNko1m2a6zv8mddBoNzngmJO2UPMgp+ntWhRtyvXqeek+CGM/5R+DYhU0g GiFsytTFGezawCv7Ui3j6i5rq82Sogc= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-2-cSbVcnAxOQ2RDgR2xI2tTQ-1; Wed, 20 Sep 2023 02:48:50 -0400 X-MC-Unique: cSbVcnAxOQ2RDgR2xI2tTQ-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 7FBD0381258E; Wed, 20 Sep 2023 06:48:50 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.39.193.241]) by smtp.corp.redhat.com (Postfix) with ESMTPS id C9DDC40C2064; Wed, 20 Sep 2023 06:48:49 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 38K6mlmE1070267 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Wed, 20 Sep 2023 08:48:47 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 38K6mkXi1070069; Wed, 20 Sep 2023 08:48:46 +0200 Date: Wed, 20 Sep 2023 08:48:46 +0200 From: Jakub Jelinek To: gcc-patches@gcc.gnu.org Cc: Tobias Burnus Subject: [committed] openmp: Add omp::decl attribute support [PR111392] Message-ID: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.1 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-0.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_NONE, RCVD_IN_SBL_CSS, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Jakub Jelinek Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1777538263225531641 X-GMAIL-MSGID: 1777538263225531641 Hi! This patch adds support for (so far C++) omp::decl attribute. For declare simd and declare variant directives it is essentially another spelling of omp::decl, except per discussions it is not allowed inside of omp::sequence attribute. For threadprivate, declare target, allocate and later groupprivate directives it should appertain to variable (or for declare target also function definitions and) declarations and where in normal syntax one specifies a list of variables (or variables and functions), either as argument of the directive or clause argument, such argument is not specified and implied to be the variable it applies to. Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk. 2023-09-20 Jakub Jelinek PR c++/111392 gcc/ * attribs.cc (decl_attributes): Don't warn on omp::directive attribute on vars or function decls if -fopenmp or -fopenmp-simd. gcc/c-family/ * c-omp.cc (c_omp_directives): Add commented out groupprivate directive entry. gcc/cp/ * parser.h (struct cp_lexer): Add in_omp_decl_attribute member. * cp-tree.h (cp_maybe_parse_omp_decl): Declare. * parser.cc (cp_parser_handle_statement_omp_attributes): Diagnose omp::decl attribute on statements. Adjust diagnostic wording for omp::decl. (cp_parser_omp_directive_args): Add DECL_P argument, set TREE_PUBLIC to it on the DEFERRED_PARSE tree. (cp_parser_omp_sequence_args): Adjust caller. (cp_parser_std_attribute): Handle omp::decl attribute. (cp_parser_omp_var_list): If parser->lexer->in_omp_decl_attribute don't expect any arguments, instead create clause or TREE_LIST for that decl. (cp_parser_late_parsing_omp_declare_simd): Adjust diagnostic wording for omp::decl. (cp_maybe_parse_omp_decl): New function. (cp_parser_omp_declare_target): If parser->lexer->in_omp_decl_attribute and first token isn't name or comma invoke cp_parser_omp_var_list. * decl2.cc (cplus_decl_attributes): Adjust diagnostic wording for omp::decl. Handle omp::decl on declarations. * name-lookup.cc (finish_using_directive): Adjust diagnostic wording for omp::decl. gcc/testsuite/ * g++.dg/gomp/attrs-19.C: New test. * g++.dg/gomp/attrs-20.C: New test. * g++.dg/gomp/attrs-21.C: New test. libgomp/ * libgomp.texi: Mark decl attribute was added to the C++ attribute syntax as implemented. Jakub --- gcc/attribs.cc.jj 2023-09-18 10:37:49.560050817 +0200 +++ gcc/attribs.cc 2023-09-19 12:29:01.495789400 +0200 @@ -719,6 +719,12 @@ decl_attributes (tree *node, tree attrib if (ns == NULL_TREE || !cxx11_attr_p) warning (OPT_Wattributes, "%qE attribute directive ignored", name); + else if ((flag_openmp || flag_openmp_simd) + && is_attribute_p ("omp", ns) + && is_attribute_p ("directive", name) + && (VAR_P (*node) + || TREE_CODE (*node) == FUNCTION_DECL)) + continue; else warning (OPT_Wattributes, "%<%E::%E%> scoped attribute directive ignored", --- gcc/c-family/c-omp.cc.jj 2023-09-18 10:37:49.577050592 +0200 +++ gcc/c-family/c-omp.cc 2023-09-19 12:29:01.507789239 +0200 @@ -3306,6 +3306,8 @@ const struct c_omp_directive c_omp_direc C_OMP_DIR_STANDALONE, false }, { "for", nullptr, nullptr, PRAGMA_OMP_FOR, C_OMP_DIR_CONSTRUCT, true }, + /* { "groupprivate", nullptr, nullptr, PRAGMA_OMP_GROUPPRIVATE, + C_OMP_DIR_DECLARATIVE, false }, */ /* { "interop", nullptr, nullptr, PRAGMA_OMP_INTEROP, C_OMP_DIR_STANDALONE, false }, */ { "loop", nullptr, nullptr, PRAGMA_OMP_LOOP, --- gcc/cp/parser.h.jj 2023-09-18 10:37:49.694049040 +0200 +++ gcc/cp/parser.h 2023-09-19 12:29:01.447790044 +0200 @@ -107,6 +107,10 @@ struct GTY (()) cp_lexer { /* The next lexer in a linked list of lexers. */ struct cp_lexer *next; + /* Set for omp::decl attribute parsing to the decl to which it + appertains. */ + tree in_omp_decl_attribute; + /* True if we should output debugging information. */ bool debugging_p; --- gcc/cp/cp-tree.h.jj 2023-09-19 09:24:19.505901636 +0200 +++ gcc/cp/cp-tree.h 2023-09-19 12:29:01.450790003 +0200 @@ -7317,6 +7317,7 @@ extern tree cp_convert_range_for (tree, extern void cp_convert_omp_range_for (tree &, tree &, tree &, tree &, tree &, tree &, tree &, tree &); extern void cp_finish_omp_range_for (tree, tree); +extern bool cp_maybe_parse_omp_decl (tree, tree); extern bool parsing_nsdmi (void); extern bool parsing_function_declarator (); extern bool parsing_default_capturing_generic_lambda_in_template (void); --- gcc/cp/parser.cc.jj 2023-09-19 09:24:19.692899089 +0200 +++ gcc/cp/parser.cc 2023-09-19 14:13:03.619970965 +0200 @@ -12001,6 +12001,12 @@ cp_parser_handle_statement_omp_attribute parser->omp_attrs_forbidden_p = false; bad = true; } + else if (TREE_PUBLIC (d)) + { + error_at (first->location, + "OpenMP % attribute on a statement"); + bad = true; + } const char *directive[3] = {}; for (int i = 0; i < 3; i++) { @@ -12022,8 +12028,9 @@ cp_parser_handle_statement_omp_attribute if (dir == NULL) { error_at (first->location, - "unknown OpenMP directive name in %" - " attribute argument"); + "unknown OpenMP directive name in %qs attribute " + "argument", + TREE_PUBLIC (d) ? "omp::decl" : "omp::directive"); continue; } c_omp_directive_kind kind = dir->kind; @@ -29366,7 +29373,7 @@ cp_parser_gnu_attribute_list (cp_parser* parsing. */ static void -cp_parser_omp_directive_args (cp_parser *parser, tree attribute) +cp_parser_omp_directive_args (cp_parser *parser, tree attribute, bool decl_p) { cp_token *first = cp_lexer_peek_nth_token (parser->lexer, 2); if (first->type == CPP_CLOSE_PAREN) @@ -29393,6 +29400,8 @@ cp_parser_omp_directive_args (cp_parser tree arg = make_node (DEFERRED_PARSE); DEFPARSE_TOKENS (arg) = cp_token_cache_new (first, last); DEFPARSE_INSTANTIATIONS (arg) = nullptr; + if (decl_p) + TREE_PUBLIC (arg) = 1; TREE_VALUE (attribute) = tree_cons (NULL_TREE, arg, TREE_VALUE (attribute)); } @@ -29440,7 +29449,7 @@ cp_parser_omp_sequence_args (cp_parser * cp_parser_required_error (parser, RT_OPEN_PAREN, false, UNKNOWN_LOCATION); else if (directive) - cp_parser_omp_directive_args (parser, attribute); + cp_parser_omp_directive_args (parser, attribute, false); else cp_parser_omp_sequence_args (parser, attribute); if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) @@ -29592,7 +29601,8 @@ cp_parser_std_attribute (cp_parser *pars if ((flag_openmp || flag_openmp_simd) && attr_ns == omp_identifier && (is_attribute_p ("directive", attr_id) - || is_attribute_p ("sequence", attr_id))) + || is_attribute_p ("sequence", attr_id) + || is_attribute_p ("decl", attr_id))) { error_at (token->location, "% attribute requires argument", attr_id); @@ -29636,7 +29646,14 @@ cp_parser_std_attribute (cp_parser *pars { if (is_attribute_p ("directive", attr_id)) { - cp_parser_omp_directive_args (parser, attribute); + cp_parser_omp_directive_args (parser, attribute, false); + return attribute; + } + else if (is_attribute_p ("decl", attr_id)) + { + TREE_VALUE (TREE_PURPOSE (attribute)) + = get_identifier ("directive"); + cp_parser_omp_directive_args (parser, attribute, true); return attribute; } else if (is_attribute_p ("sequence", attr_id)) @@ -37912,6 +37929,21 @@ static tree cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list, bool allow_deref = false) { + if (parser->lexer->in_omp_decl_attribute) + { + if (kind) + { + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + tree u = build_omp_clause (loc, kind); + OMP_CLAUSE_DECL (u) = parser->lexer->in_omp_decl_attribute; + OMP_CLAUSE_CHAIN (u) = list; + return u; + } + else + return tree_cons (parser->lexer->in_omp_decl_attribute, NULL_TREE, + list); + } + if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return cp_parser_omp_var_list_no_open (parser, kind, list, NULL, allow_deref); @@ -47843,7 +47875,9 @@ cp_parser_late_parsing_omp_declare_simd { error_at (first->location, "unknown OpenMP directive name in " - "% attribute argument"); + "%qs attribute argument", + TREE_PUBLIC (d) + ? "omp::decl" : "omp::directive"); continue; } if (dir->id != PRAGMA_OMP_DECLARE @@ -47949,6 +47983,89 @@ cp_parser_late_parsing_omp_declare_simd return attrs; } +/* D should be DEFERRED_PARSE from omp::decl attribute. If it contains + a threadprivate, groupprivate, allocate or declare target directive, + return true and parse it for DECL. */ + +bool +cp_maybe_parse_omp_decl (tree decl, tree d) +{ + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + cp_token *first = DEFPARSE_TOKENS (d)->first; + cp_token *last = DEFPARSE_TOKENS (d)->last; + const char *directive[3] = {}; + for (int j = 0; j < 3; j++) + { + tree id = NULL_TREE; + if (first + j == last) + break; + if (first[j].type == CPP_NAME) + id = first[j].u.value; + else if (first[j].type == CPP_KEYWORD) + id = ridpointers[(int) first[j].keyword]; + else + break; + directive[j] = IDENTIFIER_POINTER (id); + } + const c_omp_directive *dir = NULL; + if (directive[0]) + dir = c_omp_categorize_directive (directive[0], directive[1], + directive[2]); + if (dir == NULL) + { + error_at (first->location, + "unknown OpenMP directive name in " + "%qs attribute argument", "omp::decl"); + return false; + } + if (dir->id != PRAGMA_OMP_THREADPRIVATE + /* && dir->id != PRAGMA_OMP_GROUPPRIVATE */ + && dir->id != PRAGMA_OMP_ALLOCATE + && (dir->id != PRAGMA_OMP_DECLARE + || strcmp (directive[1], "target") != 0)) + return false; + + if (!flag_openmp && !dir->simd) + return true; + + cp_parser *parser = the_parser; + cp_lexer *lexer = cp_lexer_alloc (); + lexer->debugging_p = parser->lexer->debugging_p; + lexer->in_omp_decl_attribute = decl; + vec_safe_reserve (lexer->buffer, last - first + 3, true); + cp_token tok = {}; + tok.type = CPP_PRAGMA; + tok.keyword = RID_MAX; + tok.u.value = build_int_cst (NULL, dir->id); + tok.location = first->location; + lexer->buffer->quick_push (tok); + while (++first < last) + lexer->buffer->quick_push (*first); + tok = {}; + tok.type = CPP_PRAGMA_EOL; + tok.keyword = RID_MAX; + tok.location = last->location; + lexer->buffer->quick_push (tok); + tok = {}; + tok.type = CPP_EOF; + tok.keyword = RID_MAX; + tok.location = last->location; + lexer->buffer->quick_push (tok); + lexer->next = parser->lexer; + lexer->next_token = lexer->buffer->address (); + lexer->last_token = lexer->next_token + + lexer->buffer->length () + - 1; + lexer->in_omp_attribute_pragma = true; + parser->lexer = lexer; + /* Move the current source position to that of the first token in the + new lexer. */ + cp_lexer_set_source_position_from_token (lexer->next_token); + cp_parser_pragma (parser, pragma_external, NULL); + + return true; +} + /* Helper for cp_parser_omp_declare_target, handle one to or link clause on #pragma omp declare target. Return false if errors were reported. */ @@ -48048,7 +48165,8 @@ cp_parser_omp_declare_target (cp_parser clauses = cp_parser_omp_all_clauses (parser, OMP_DECLARE_TARGET_CLAUSE_MASK, "#pragma omp declare target", pragma_tok); - else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + else if (parser->lexer->in_omp_decl_attribute + || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_ENTER, clauses); --- gcc/cp/decl2.cc.jj 2023-09-18 10:37:49.634049836 +0200 +++ gcc/cp/decl2.cc 2023-09-19 12:29:01.495789400 +0200 @@ -1738,16 +1738,34 @@ cplus_decl_attributes (tree *decl, tree { tree name = get_attribute_name (*pa); if (is_attribute_p ("directive", name) - || is_attribute_p ("sequence", name)) + || is_attribute_p ("sequence", name) + || is_attribute_p ("decl", name)) { - if (!diagnosed) + const char *p = NULL; + if (TREE_VALUE (*pa) == NULL_TREE) + p = IDENTIFIER_POINTER (name); + for (tree a = TREE_VALUE (*pa); a; a = TREE_CHAIN (a)) { - error ("% not allowed to be specified in this " - "context", name); + tree d = TREE_VALUE (a); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + if (TREE_PUBLIC (d) + && (VAR_P (*decl) + || TREE_CODE (*decl) == FUNCTION_DECL) + && cp_maybe_parse_omp_decl (*decl, d)) + continue; + p = TREE_PUBLIC (d) ? "decl" : "directive"; + } + if (p && !diagnosed) + { + error ("% not allowed to be specified in " + "this context", p); diagnosed = true; } - *pa = TREE_CHAIN (*pa); - continue; + if (p) + { + *pa = TREE_CHAIN (*pa); + continue; + } } } pa = &TREE_CHAIN (*pa); --- gcc/cp/name-lookup.cc.jj 2023-09-19 09:24:19.632899906 +0200 +++ gcc/cp/name-lookup.cc 2023-09-19 12:29:01.451789990 +0200 @@ -8402,12 +8402,24 @@ finish_using_directive (tree target, tre else if ((flag_openmp || flag_openmp_simd) && get_attribute_namespace (a) == omp_identifier && (is_attribute_p ("directive", name) - || is_attribute_p ("sequence", name))) + || is_attribute_p ("sequence", name) + || is_attribute_p ("decl", name))) { if (!diagnosed) - error ("% not allowed to be specified in this " - "context", name); - diagnosed = true; + { + if (tree ar = TREE_VALUE (a)) + { + tree d = TREE_VALUE (ar); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + error ("% not allowed to be specified in " + "this context", + TREE_PUBLIC (d) ? "decl" : "directive"); + } + else + error ("% not allowed to be specified in this " + "context", name); + diagnosed = true; + } } else warning (OPT_Wattributes, "%qD attribute directive ignored", name); --- gcc/testsuite/g++.dg/gomp/attrs-19.C.jj 2023-09-19 13:46:37.616293306 +0200 +++ gcc/testsuite/g++.dg/gomp/attrs-19.C 2023-09-19 15:48:01.254979254 +0200 @@ -0,0 +1,68 @@ +// { dg-do compile { target c++11 } } + +void foo1 (); + +void +foo () +{ + [[omp::decl (declare variant (foo1) match (construct={parallel,for}))]] + extern void foo2 (); + [[omp::sequence (directive (parallel), directive (for))]] + for (int i = 0; i < 5; i++) + foo2 (); + [[omp::decl (declare simd simdlen(4) linear(l) aligned(p:4) uniform(p) inbranch), + omp::directive (declare simd simdlen(8) notinbranch)]] + extern int foo3 (int l, int *p); + [[omp::directive (declare simd simdlen(4) linear(l) aligned(p:4) uniform(p) inbranch), + omp::decl (declare simd simdlen(8) notinbranch)]] + extern int foo4 (int l, int *p); + [[omp::decl (declare simd simdlen(4) linear(l) aligned(p:4) uniform(p) inbranch), + omp::decl (declare simd simdlen(8) notinbranch)]] + extern int foo5 (int l, int *p); +} + +void bar1 (); + +void +bar () +{ + [[using omp : decl (declare variant (bar1), match (construct={parallel,for}))]] // { dg-warning "attribute using prefix only available with" "" { target c++14_down } } + extern void bar2 (); + [[using omp : sequence (directive (parallel), directive (for))]] // { dg-warning "attribute using prefix only available with" "" { target c++14_down } } + for (int i = 0; i < 5; i++) + bar2 (); + [[omp::decl (declare simd, simdlen(4), linear(l), aligned(p:4),uniform(p),inbranch), + omp::directive (declare simd simdlen(8) notinbranch)]] + extern int bar3 (int l, int *p); + [[using omp : directive (declare simd,simdlen(4),linear(l),aligned(p:4),uniform(p),inbranch), // { dg-warning "attribute using prefix only available with" "" { target c++14_down } } + decl (declare simd, simdlen(8), notinbranch)]] + extern int bar4 (int l, int *p); + [[omp::decl (declare simd, simdlen(4), linear(l), aligned(p:4), uniform(p), inbranch), + omp::decl (declare simd, simdlen(8), notinbranch)]] + extern int bar5 (int l, int *p); +} + +struct S { S (); ~S (); int s; }; + +[[omp::decl (threadprivate)]] int t1, t2; +int x1, t3 [[omp::decl (threadprivate)]], x2, t4 [[omp::decl (threadprivate)]] [5]; +[[maybe_unused, omp::decl (threadprivate)]] int t5, t6; +[[using omp : decl (threadprivate)]] S t7, t8; // { dg-warning "attribute using prefix only available with" "" { target c++14_down } } +[[using omp : decl (declare target enter device_type (host))]] int d1, d2, d3 (int, int), d4; // { dg-warning "attribute using prefix only available with" "" { target c++14_down } } +int x3, d5 [[omp::decl (declare target, enter, device_type (any))]], d6 [[omp::decl (declare target link)]], x4; +int d7 [[omp::decl (declare target)]]; +[[using omp : decl (declare target), decl (declare target)]] int d8, d9; // { dg-warning "attribute using prefix only available with" "" { target c++14_down } } + +void +baz () +{ + [[omp::decl (threadprivate)]] static int t1, t2; + static int x1, t3 [[omp::decl (threadprivate)]], x2, t4 [[omp::decl (threadprivate)]] [5]; + [[maybe_unused, omp::decl (threadprivate)]] extern int t5, t6; + [[using omp : decl (declare target enter)]] extern int d1, d2, d3 (int, int), d4; // { dg-warning "attribute using prefix only available with" "" { target c++14_down } } + static int x3, d5 [[omp::decl (declare target, enter, device_type (any))]], d6 [[omp::decl (declare target link)]], x4; + ++t1; ++t2; + ++t3; ++t4[2]; + ++t5; ++t6; + ++d1; +} --- gcc/testsuite/g++.dg/gomp/attrs-20.C.jj 2023-09-19 13:48:33.998732461 +0200 +++ gcc/testsuite/g++.dg/gomp/attrs-20.C 2023-09-19 13:57:54.018211210 +0200 @@ -0,0 +1,240 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-fopenmp -ffat-lto-objects -fdump-tree-gimple" } + +extern "C" void abort (); + +[[omp::decl (declare simd, linear (l))]] extern int f1 (int l); +extern int f2 (int), f3 [[omp::decl (declare simd, uniform (m))]] (int m), f4 (int), z; +[[omp::decl (declare simd, linear (l), simdlen(4))]] extern int f5 [[omp::decl (declare simd uniform (l) simdlen (8) notinbranch)]] (int l); + +int +f1 (int l) +{ + return l; +} + +// { dg-final { scan-assembler-times "_ZGVbM4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } + +int +f2 (int l) +{ + return l + 1; +} + +// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f2i:" { target { i?86-*-* x86_64-*-* } } } } + +int +f3 (int l) +{ + return l + 2; +} + +// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } + +int +f4 (int l) +{ + return l + 3; +} + +// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f4i:" { target { i?86-*-* x86_64-*-* } } } } + +int +f5 (int l) +{ // { dg-warning "GCC does not currently support simdlen 8 for type 'int'" "" { target aarch64*-*-* } .-1 } + return l + 4; +} + +// { dg-final { scan-assembler-times "_ZGVbM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]M8u__Z2f5i:" { target { i?86-*-* x86_64-*-* } } } } + +[[omp::decl (declare simd, linear (l), simdlen(4), notinbranch), + omp::decl (declare simd, uniform (l), simdlen(4), inbranch)]] +int +f6 [[using omp : decl (declare simd uniform (l) simdlen (8), notinbranch), // { dg-warning "attribute using prefix only available with" "" { target c++14_down } } + decl (declare simd, linear (l), simdlen (8), inbranch)]] (int l) +{ // { dg-warning "GCC does not currently support simdlen 8 for type 'int'" "" { target aarch64*-*-* } .-2 } + return l + 5; +} + +// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]M4l__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]N4u__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]M8u__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]N8l__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } } + +int +f7 (int l) +{ + return l + 6; +} + +// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f7i:" { target { i?86-*-* x86_64-*-* } } } } + +int +f8 (int l) +{ + return l + 7; +} + +// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f8i:" { target { i?86-*-* x86_64-*-* } } } } + +[[omp::decl (declare variant (f7), match (construct={parallel})), + omp::decl (declare simd uniform (l), simdlen(4))]] +int +f9 [[omp::decl (declare simd uniform (l) simdlen (8)), + omp::decl (declare variant (f8) match (construct={parallel,for}))]] (int l) +{ // { dg-warning "GCC does not currently support simdlen 8 for type 'int'" "" { target aarch64*-*-* } .-2 } + return l + 8; +} + +// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } + +int z; + +void +test () +{ + [[omp::directive (parallel)]] + if (f9 (3) != 9) + abort (); + [[omp::directive (parallel for)]] + for (int i = 0; i < 1; i++) + if (f9 (4) != 11) + abort (); + if (f9 (5) != 13) + abort (); +} + +// { dg-final { scan-tree-dump-times " = f7 \\\(3\\\);" 1 "gimple" } } +// { dg-final { scan-tree-dump-times " = f8 \\\(4\\\);" 1 "gimple" } } +// { dg-final { scan-tree-dump-times " = f9 \\\(5\\\);" 1 "gimple" } } + +template +int +f10 (int x) +{ + return x + N; +} + +template [[omp::decl (declare simd, notinbranch)]] int f10<0> (int); + +// { dg-final { scan-assembler-times "_ZGVbN4v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } + +template int f10<1> [[omp::decl (declare simd inbranch linear(x))]] (int x); + +// { dg-final { scan-assembler-times "_ZGVbM4l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } + +template +int f11 (int); + +template <> [[omp::decl (declare simd, inbranch)]] int +f11<0> (int x) +{ + return x; +} + +// { dg-final { scan-assembler-times "_ZGVbM4v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } + +template <> int +f11<1> [[omp::decl (declare simd, notinbranch, linear (y))]] (int y) +{ + return y; +} + +// { dg-final { scan-assembler-times "_ZGVbN4l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } + +struct S +{ + [[omp::decl (declare simd, inbranch, uniform (this))]] int f12 (int x); + int f13 [[gnu::noinline, omp::decl (declare simd notinbranch uniform (this) linear (y))]] (int y) { return y; } +}; + +int +S::f12 (int x) +{ + return x; +} + +// { dg-final { scan-assembler-times "_ZGVbM4uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } + +// { dg-final { scan-assembler-times "_ZGVbN4ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } + +int +f14 (S &p, int x) +{ + return p.f13 (x); +} --- gcc/testsuite/g++.dg/gomp/attrs-21.C.jj 2023-09-19 14:53:50.901137744 +0200 +++ gcc/testsuite/g++.dg/gomp/attrs-21.C 2023-09-19 16:30:26.031973827 +0200 @@ -0,0 +1,27 @@ +// { dg-do compile { target c++11 } } + +void +foo () +{ + [[omp::decl]] int v1; // { dg-error "'omp::decl' attribute requires argument" } + [[omp::decl ()]] int v2; // { dg-error "expected OpenMP directive name" } + // { dg-error "'omp::directive' not allowed to be specified in this context" "" { target *-*-* } .-1 } + [[omp::decl (nonexistent foobar)]] int v3; // { dg-error "unknown OpenMP directive name in 'omp::decl' attribute argument" } + // { dg-error "'omp::decl' not allowed to be specified in this context" "" { target *-*-* } .-1 } + [[omp::sequence(decl(threadprivate))]] int v4; // { dg-error "expected 'directive' or 'sequence'" } + // { dg-error "'omp::directive' not allowed to be specified in this context" "" { target *-*-* } .-1 } + [[omp::sequence(omp::decl(threadprivate))]] int v5; // { dg-error "expected 'directive' or 'sequence'" } + // { dg-error "'omp::directive' not allowed to be specified in this context" "" { target *-*-* } .-1 } + [[omp::decl (barrier)]]; // { dg-error "OpenMP 'omp::decl' attribute on a statement" } + [[omp::decl (parallel)]] {}; // { dg-error "OpenMP 'omp::decl' attribute on a statement" } + extern int [[omp::decl (threadprivate)]] *v6; // { dg-warning "attribute ignored" } + [[omp::decl (threadprivate (v5))]] static int v7; // { dg-error "expected end of line before '\\\(' token" } + extern int v8; + [[omp::decl (declare target (v8))]] static int v9; // { dg-error "expected end of line before '\\\(' token" } + [[omp::decl (declare target enter (v8))]] static int v10; // { dg-error "expected an OpenMP clause before '\\\(' token" } + [[omp::decl (declare target, link (v9))]] static int v11; // { dg-error "expected an OpenMP clause before '\\\(' token" } + [[omp::decl (declare target device_type (any))]] static int v12; // { dg-error "directive with only 'device_type' clause" } +} + +int i; +[[omp::decl (assume (i < 42))]]; // { dg-error "OpenMP 'omp::decl' attribute on a statement" } --- libgomp/libgomp.texi.jj 2023-09-11 11:05:47.590726871 +0200 +++ libgomp/libgomp.texi 2023-09-19 17:41:42.002500222 +0200 @@ -444,7 +444,7 @@ Technical Report (TR) 11 is the first pr @item Features deprecated in versions 5.2, 5.1 and 5.0 were removed @tab N/A @tab Backward compatibility @item The @code{decl} attribute was added to the C++ attribute syntax - @tab N @tab + @tab Y @tab @item @code{_ALL} suffix to the device-scope environment variables @tab P @tab Host device number wrongly accepted @item For Fortran, @emph{locator list} can be also function reference with