From patchwork Tue Nov 3 21:17:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Sidwell X-Patchwork-Id: 1393436 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=acm.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=TP8ykAI5; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CQjLK6Lqsz9sVp for ; Wed, 4 Nov 2020 08:18:01 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A8F0F398784F; Tue, 3 Nov 2020 21:17:59 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-qk1-x731.google.com (mail-qk1-x731.google.com [IPv6:2607:f8b0:4864:20::731]) by sourceware.org (Postfix) with ESMTPS id 510AC398753E for ; Tue, 3 Nov 2020 21:17:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 510AC398753E Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=acm.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=nathanmsidwell@gmail.com Received: by mail-qk1-x731.google.com with SMTP id o205so9848601qke.10 for ; Tue, 03 Nov 2020 13:17:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:subject:to:references:message-id:date:user-agent :mime-version:in-reply-to:content-language; bh=Dot6s5zwwKJ5WPc+Th4IpO1mcWa2b+Sn+461/Wblm+4=; b=TP8ykAI503dtidNvhWuDGDlpnya3A8RzGD6FUjcZYZAsOj58wbnVJ5qhRjohGjlUz+ TiGx9ZAPn1e4ihrUubHBKUGI2Q8BbDF25zOpz7Ez0mmE4fa3MoESHozoL+T2HChKPXBM ReEPeKUAmDVKLM2YcoqvIXOeoKUnaWFGrj5+R36OEtMEIjA76UkxiZirwM4KiCimOMKf AtjpUNLE5qXoXy1WPfY8FEuq7xYiP+3QcK0FPJtb9J2ze1YibgBszAo0roj1L1lmzgV0 TP3OTZUZLKG9f/XeoQZLPCwr9wW8rn+paIly6viCST9JxkfpvTj7XN8PpeERoasAJm6d RA1w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:subject:to:references:message-id :date:user-agent:mime-version:in-reply-to:content-language; bh=Dot6s5zwwKJ5WPc+Th4IpO1mcWa2b+Sn+461/Wblm+4=; b=MW33D5ZlvrepIDrYtqItd1+LKkVEw8YYe0qqln0tOCljkZi1TFy8Dt6jnbCdaFzMWp SncyE6Kg04d27NfxhasZ9LrZZvX4Y9rAitN4z1S47JXTkgVlTYqNwSI1ntX6WY4L9FGR slgKf6Bg0XNJzTwj8FK8cFC4a01NJ3+BfLciJ2SzyqRUXiAWmwUmGXC4VGSyVAeed58c +6EUxY3D3wJcWUznN0koMVSNidV6gV4XvHaLXAQ3OAdsbcc2A84y7QLt8CXJifaVrVNi KAU5ck6E/DBzFMf+Uq/+A1I//411puDLA6Gti3nPldfi9w0EwZiDqE7sOjoZX3hfTSSy 3m9g== X-Gm-Message-State: AOAM5313pJBdc+ejXKeQkZ4B71zWPfVJO+XZrbwVQaIX8/LEVU+/HIAR 6Zi+3V/cHRpIFhH85+cW5P4= X-Google-Smtp-Source: ABdhPJzfljk83CVO9yjIVON/thPqOi5DV4FmpCvQVHKToUZ+eL233qQq6t65sMeXMG4bupTLHJM5vA== X-Received: by 2002:a37:2712:: with SMTP id n18mr21068243qkn.405.1604438270727; Tue, 03 Nov 2020 13:17:50 -0800 (PST) Received: from ?IPv6:2620:10d:c0a8:1102:e5ef:7eb4:1609:98bb? ([2620:10d:c091:480::1:bc2d]) by smtp.googlemail.com with ESMTPSA id q70sm11373847qka.87.2020.11.03.13.17.49 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 03 Nov 2020 13:17:49 -0800 (PST) From: Nathan Sidwell Subject: [27/32] parser To: GCC Patches , Jason Merrill , Richard Biener References: <7fc9e868-3db9-4972-ed67-6ff249f549c3@acm.org> <4d14b230-3263-9a13-3159-c4853f282761@acm.org> <688bd28f-5998-0def-8c40-03b817832d63@acm.org> <89819c10-e86d-9b01-5673-5223a525a135@acm.org> <35879e15-d74a-c664-4d44-15f4b3783d77@acm.org> <9ae23c4c-67a5-a267-c939-5a96e9488612@acm.org> <6666545b-0583-4812-4745-d51994465818@acm.org> <1ab99df5-3997-0895-c979-f8529f476df7@acm.org> <97e9477b-7173-b7f9-a884-616b972c57ba@acm.org> <01f091a5-cd8b-60b6-9552-2318ecd07025@acm.org> <5c533ebe-440d-188e-5bdb-38c14898852c@acm.org> <9e6ec23c-6b36-de70-7630-55562583696f@acm.org> <3d138aa4-df19-df5d-54c6-ec7299749f0f@acm.org> Message-ID: Date: Tue, 3 Nov 2020 16:17:48 -0500 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.5.0 MIME-Version: 1.0 In-Reply-To: Content-Language: en-US X-Spam-Status: No, score=-11.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces@gcc.gnu.org Sender: "Gcc-patches" the parser changes are two-fold a) call out to the token inspector added to lex, so that module control lines are processed during tokenization b) adding parser support for module and import declarations. As mentioned in the introduction, I do not handle the case of textually parsing a definition when an existing definition is already know via (header-unit) import. You'll get a multiple-definition error. nathan diff --git c/gcc/cp/parser.c w/gcc/cp/parser.c index dd8c4b56bd0..98ca9aae082 100644 --- c/gcc/cp/parser.c +++ w/gcc/cp/parser.c @@ -646,9 +646,17 @@ cp_lexer_new_main (void) /* Put the first token in the buffer. */ cp_token *tok = lexer->buffer->quick_push (token); + uintptr_t coro = 0; + if (modules_p ()) + coro = module_token_cdtor (parse_in, coro); + /* Get the remaining tokens from the preprocessor. */ while (tok->type != CPP_EOF) { + if (coro) + /* Process the previous token. */ + module_token_lang (tok->type, tok->keyword, tok->u.value, + tok->location, coro); tok = vec_safe_push (lexer->buffer, cp_token ()); cp_lexer_get_preprocessor_token (C_LEX_STRING_NO_JOIN, tok); } @@ -658,10 +666,15 @@ cp_lexer_new_main (void) + lexer->buffer->length () - 1; + if (coro) + module_token_cdtor (parse_in, coro); + /* Subsequent preprocessor diagnostics should use compiler diagnostic functions to get the compiler source location. */ done_lexing = true; + maybe_check_all_macros (parse_in); + gcc_assert (!lexer->next_token->purged_p); return lexer; } @@ -834,6 +847,8 @@ cp_lexer_get_preprocessor_token (unsigned flags, cp_token *token) token->purged_p = false; token->error_reported = false; token->tree_check_p = false; + /* Usually never see a zero, but just in case ... */ + token->main_source_p = line_table->depth <= 1; /* On some systems, some header files are surrounded by an implicit extern "C" block. Set a flag in the token if it @@ -2179,6 +2194,28 @@ static tree cp_parser_implicitly_scoped_statement static void cp_parser_already_scoped_statement (cp_parser *, bool *, const token_indent_info &); +/* State of module-declaration parsing. */ +enum module_parse +{ + MP_NOT_MODULE, /* Not a module. */ + + _MP_UNUSED, + + MP_FIRST, /* First declaration of TU. */ + MP_GLOBAL, /* Global Module Fragment. */ + + MP_PURVIEW_IMPORTS, /* Imports of a module. */ + MP_PURVIEW, /* Purview of a named module. */ + + MP_PRIVATE_IMPORTS, /* Imports of a Private Module Fragment. */ + MP_PRIVATE, /* Private Module Fragment. */ +}; + +static module_parse cp_parser_module_declaration + (cp_parser *parser, module_parse, bool exporting); +static void cp_parser_import_declaration + (cp_parser *parser, module_parse, bool exporting); + /* Declarations [gram.dcl.dcl] */ static void cp_parser_declaration_seq_opt @@ -3393,6 +3430,7 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id, } else error_at (location, "%qE does not name a type", id); + /* If we're in a template class, it's possible that the user was referring to a type from a base class. For example: @@ -3400,14 +3438,23 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id, template struct B : public A { X x; }; The user should have said "typename A::X". */ - if (cxx_dialect < cxx11 && id == ridpointers[(int)RID_CONSTEXPR]) + if (cxx_dialect < cxx11 && C_RID_CODE (id) == RID_CONSTEXPR) inform (location, "C++11 % only available with " "%<-std=c++11%> or %<-std=gnu++11%>"); - else if (cxx_dialect < cxx11 && id == ridpointers[(int)RID_NOEXCEPT]) + else if (cxx_dialect < cxx11 && C_RID_CODE (id) == RID_NOEXCEPT) inform (location, "C++11 % only available with " "%<-std=c++11%> or %<-std=gnu++11%>"); - else if (cxx_dialect < cxx11 - && TREE_CODE (id) == IDENTIFIER_NODE + else if (TREE_CODE (id) == IDENTIFIER_NODE + && (id_equal (id, "module") || id_equal (id, "import"))) + { + if (!modules_p ()) + inform (location, "%qE only available with %<-fmodules-ts%>", id); + else + inform (location, "%qE was not recognized as a module control-line", + id); + } + else if (TREE_CODE (id) == IDENTIFIER_NODE + && cxx_dialect < cxx11 && id_equal (id, "thread_local")) inform (location, "C++11 % only available with " "%<-std=c++11%> or %<-std=gnu++11%>"); @@ -3699,6 +3746,13 @@ cp_parser_skip_to_closing_parenthesis_1 (cp_parser *parser, condop_depth--; break; + case CPP_KEYWORD: + if (token->keyword != RID__EXPORT + && token->keyword != RID__MODULE + && token->keyword != RID__IMPORT) + break; + /* FALLTHROUGH */ + case CPP_PRAGMA: /* We fell into a pragma. Skip it, and continue. */ cp_parser_skip_to_pragma_eol (parser, recovering ? token : nullptr); @@ -3795,6 +3849,13 @@ cp_parser_skip_to_end_of_statement (cp_parser* parser) ++nesting_depth; break; + case CPP_KEYWORD: + if (token->keyword != RID__EXPORT + && token->keyword != RID__MODULE + && token->keyword != RID__IMPORT) + break; + /* FALLTHROUGH */ + case CPP_PRAGMA: /* We fell into a pragma. Skip it, and continue or return. */ cp_parser_skip_to_pragma_eol (parser, token); @@ -3877,6 +3938,13 @@ cp_parser_skip_to_end_of_block_or_statement (cp_parser* parser) nesting_depth++; break; + case CPP_KEYWORD: + if (token->keyword != RID__EXPORT + && token->keyword != RID__MODULE + && token->keyword != RID__IMPORT) + break; + /* FALLTHROUGH */ + case CPP_PRAGMA: /* Skip it, and continue or return. */ cp_parser_skip_to_pragma_eol (parser, token); @@ -4758,6 +4826,10 @@ cp_parser_translation_unit (cp_parser* parser) push_deferring_access_checks (flag_access_control ? dk_no_deferred : dk_no_check); + module_parse mp_state = MP_NOT_MODULE; + if (modules_p () && !header_module_p ()) + mp_state = MP_FIRST; + bool implicit_extern_c = false; /* Parse until EOF. */ @@ -4781,6 +4853,55 @@ cp_parser_translation_unit (cp_parser* parser) if (token->type == CPP_EOF) break; + if (modules_p ()) + { + /* Top-level module declarations are ok, and change the + portion of file we're in. Top-level import declarations + are significant for the import portions. */ + + cp_token *next = token; + bool exporting = token->keyword == RID__EXPORT; + if (exporting) + { + cp_lexer_consume_token (parser->lexer); + next = cp_lexer_peek_token (parser->lexer); + } + if (next->keyword == RID__MODULE) + { + mp_state + = cp_parser_module_declaration (parser, mp_state, exporting); + continue; + } + else if (next->keyword == RID__IMPORT) + { + if (mp_state == MP_FIRST) + mp_state = MP_NOT_MODULE; + cp_parser_import_declaration (parser, mp_state, exporting); + continue; + } + else + gcc_checking_assert (!exporting); + + if (mp_state == MP_GLOBAL && token->main_source_p) + { + static bool warned = false; + if (!warned) + { + warned = true; + error_at (token->location, + "global module fragment contents must be" + " from preprocessor inclusion"); + } + } + } + + /* This relies on the ordering of module_parse values. */ + if (mp_state == MP_PURVIEW_IMPORTS || mp_state == MP_PRIVATE_IMPORTS) + /* We're no longer in the import portion of a named module. */ + mp_state = module_parse (mp_state + 1); + else if (mp_state == MP_FIRST) + mp_state = MP_NOT_MODULE; + if (token->type == CPP_CLOSE_BRACE) { cp_parser_error (parser, "expected declaration"); @@ -13449,9 +13570,234 @@ cp_parser_already_scoped_statement (cp_parser* parser, bool *if_p, } } +/* Modules */ + +/* Parse a module-name, + identifier + module-name . identifier + header-name + + Returns a pointer to module object, NULL. */ + +static module_state * +cp_parser_module_name (cp_parser *parser) +{ + cp_token *token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_HEADER_NAME) + { + cp_lexer_consume_token (parser->lexer); + + return get_module (token->u.value); + } + + module_state *parent = NULL; + bool partitioned = false; + if (token->type == CPP_COLON && named_module_p ()) + { + partitioned = true; + cp_lexer_consume_token (parser->lexer); + } + + for (;;) + { + if (cp_lexer_peek_token (parser->lexer)->type != CPP_NAME) + { + cp_parser_error (parser, "expected module-name"); + break; + } + + tree name = cp_lexer_consume_token (parser->lexer)->u.value; + parent = get_module (name, parent, partitioned); + token = cp_lexer_peek_token (parser->lexer); + if (!partitioned && token->type == CPP_COLON) + partitioned = true; + else if (token->type != CPP_DOT) + break; + + cp_lexer_consume_token (parser->lexer); + } + + return parent; +} + +/* Named module-declaration + __module ; PRAGMA_EOL + __module private ; PRAGMA_EOL (unimplemented) + [__export] __module module-name attr-spec-seq-opt ; PRAGMA_EOL +*/ + +static module_parse +cp_parser_module_declaration (cp_parser *parser, module_parse mp_state, + bool exporting) +{ + /* We're a pseudo pragma. */ + parser->lexer->in_pragma = true; + cp_token *token = cp_lexer_consume_token (parser->lexer); + + if (mp_state == MP_FIRST && !exporting + && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + { + /* Start global module fragment. */ + cp_lexer_consume_token (parser->lexer); + module_kind |= MK_GLOBAL; + mp_state = MP_GLOBAL; + cp_parser_require_pragma_eol (parser, token); + } + else if (!exporting + && cp_lexer_next_token_is (parser->lexer, CPP_COLON) + && cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_PRIVATE) + && cp_lexer_nth_token_is (parser->lexer, 3, CPP_SEMICOLON)) + { + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + cp_parser_require_pragma_eol (parser, token); + + if ((mp_state != MP_PURVIEW && mp_state != MP_PURVIEW_IMPORTS) + || !module_interface_p () || module_partition_p ()) + error_at (token->location, + "private module fragment not permitted here"); + else + { + mp_state = MP_PRIVATE_IMPORTS; + sorry_at (token->location, "private module fragment"); + } + } + else if (mp_state != MP_FIRST && mp_state != MP_GLOBAL) + { + error_at (token->location, "module-declaration not permitted here"); + skip_eol: + cp_parser_skip_to_pragma_eol (parser, token); + } + else + { + module_state *mod = cp_parser_module_name (parser); + tree attrs = cp_parser_attributes_opt (parser); + + mp_state = MP_PURVIEW_IMPORTS; + if (!mod || !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) + goto skip_eol; + + declare_module (mod, token->location, exporting, attrs, parse_in); + cp_parser_require_pragma_eol (parser, token); + } + + return mp_state; +} + +/* Import-declaration + [__export] __import module-name attr-spec-seq-opt ; PRAGMA_EOL */ + +static void +cp_parser_import_declaration (cp_parser *parser, module_parse mp_state, + bool exporting) +{ + /* We're a pseudo pragma. */ + parser->lexer->in_pragma = true; + cp_token *token = cp_lexer_consume_token (parser->lexer); + + if (mp_state != MP_PURVIEW_IMPORTS + && mp_state != MP_PRIVATE_IMPORTS + && module_purview_p () + && !global_purview_p ()) + { + error_at (token->location, "post-module-declaration" + " imports must be contiguous"); + note_lexer: + inform (token->location, "perhaps insert a line break, or other" + " disambiguation, to prevent this being considered a" + " module control-line"); + skip_eol: + cp_parser_skip_to_pragma_eol (parser, token); + } + else if (current_scope () != global_namespace) + { + error_at (token->location, "import-declaration must be at global scope"); + goto note_lexer; + } + else + { + module_state *mod = cp_parser_module_name (parser); + tree attrs = cp_parser_attributes_opt (parser); + + if (!mod || !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) + goto skip_eol; + cp_parser_require_pragma_eol (parser, token); + + if (parser->in_unbraced_linkage_specification_p) + error_at (token->location, "import cannot appear directly in" + " a linkage-specification"); + + if (attrs && module_purview_p () && !global_purview_p () + && private_lookup_attribute ("__translated", + strlen ("__translated"), attrs)) + error_at (token->location, "post-module-declaration imports" + " must not be include-translated"); + else if ((mp_state == MP_PURVIEW_IMPORTS + || mp_state == MP_PRIVATE_IMPORTS) + && !token->main_source_p) + error_at (token->location, "post-module-declaration imports" + " must not be from header inclusion"); + + import_module (mod, token->location, exporting, attrs, parse_in); + } +} + +/* export-declaration. + + export declaration + export { declaration-seq-opt } */ + +static void +cp_parser_module_export (cp_parser *parser) +{ + gcc_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_EXPORT)); + cp_token *token = cp_lexer_consume_token (parser->lexer); + + if (!module_interface_p ()) + error_at (token->location, + "%qE may only occur after a module interface declaration", + token->u.value); + + bool braced = cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE); + + unsigned mk = module_kind; + if (module_exporting_p ()) + error_at (token->location, + "%qE may only occur once in an export declaration", + token->u.value); + module_kind |= MK_EXPORTING; + + if (braced) + { + cp_ensure_no_omp_declare_simd (parser); + cp_ensure_no_oacc_routine (parser); + + cp_lexer_consume_token (parser->lexer); + cp_parser_declaration_seq_opt (parser); + cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + } + else + { + /* Explicitly check if the next tokens might be a + module-directive line, so we can give a clearer error message + about why the directive will be rejected. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID__MODULE) + || cp_lexer_next_token_is_keyword (parser->lexer, RID__IMPORT) + || cp_lexer_next_token_is_keyword (parser->lexer, RID__EXPORT)) + error_at (token->location, "% not part of following" + " module-directive"); + cp_parser_declaration (parser); + } + + module_kind = mk; +} + /* Declarations [gram.dcl.dcl] */ -/* Parse an optional declaration-sequence. +/* Parse an optional declaration-sequence. TOP_LEVEL is true, if this + is the top-level declaration sequence. That affects whether we + deal with module-preamble. declaration-seq: declaration @@ -13486,6 +13832,14 @@ cp_parser_declaration_seq_opt (cp_parser* parser) C++17: deduction-guide + modules: + (all these are only allowed at the outermost level, check + that semantically, for better diagnostics) + module-declaration + module-export-declaration + module-import-declaration + export-declaration + GNU extension: declaration: @@ -13538,10 +13892,28 @@ cp_parser_declaration (cp_parser* parser) else cp_parser_explicit_instantiation (parser); } - /* If the next token is `export', then we have a template - declaration. */ + /* If the next token is `export', it's new-style modules or + old-style template. */ else if (token1->keyword == RID_EXPORT) - cp_parser_template_declaration (parser, /*member_p=*/false); + { + if (!modules_p ()) + cp_parser_template_declaration (parser, /*member_p=*/false); + else + cp_parser_module_export (parser); + } + else if (token1->keyword == RID__EXPORT + || token1->keyword == RID__IMPORT + || token1->keyword == RID__MODULE) + { + bool exporting = token1->keyword == RID__EXPORT; + cp_token *next = exporting ? token2 : token1; + if (exporting) + cp_lexer_consume_token (parser->lexer); + if (next->keyword == RID__MODULE) + cp_parser_module_declaration (parser, MP_NOT_MODULE, exporting); + else + cp_parser_import_declaration (parser, MP_NOT_MODULE, exporting); + } /* If the next token is `extern', 'static' or 'inline' and the one after that is `template', we have a GNU extended explicit instantiation directive. */ @@ -16027,8 +16399,13 @@ cp_parser_template_declaration (cp_parser* parser, bool member_p) { /* Consume the `export' token. */ cp_lexer_consume_token (parser->lexer); - /* Warn that we do not support `export'. */ - warning (0, "keyword % not implemented, and will be ignored"); + /* Warn that this use of export is deprecated. */ + if (cxx_dialect < cxx11) + warning (0, "keyword % not implemented, and will be ignored"); + else if (cxx_dialect < cxx20) + warning (0, "keyword % is deprecated, and is ignored"); + else + warning (0, "keyword % is enabled with %<-fmodules-ts%>"); } cp_parser_template_declaration_after_export (parser, member_p); @@ -17749,7 +18126,6 @@ cp_parser_explicit_specialization (cp_parser* parser) /* Give it C++ linkage to avoid confusing other parts of the front end. */ push_lang_context (lang_name_cplusplus); - need_lang_pop = true; } /* Let the front end know that we are beginning a specialization. */ @@ -28483,11 +28861,6 @@ cp_parser_lookup_name (cp_parser *parser, tree name, prefer_type_arg (tag_type), /*complain=*/true); - /* If we have a single function from a using decl, pull it out. */ - if (TREE_CODE (decl) == OVERLOAD - && !really_overloaded_fn (decl)) - decl = OVL_FUNCTION (decl); - if (pushed_scope) pop_scope (pushed_scope); } @@ -29206,6 +29579,14 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, /* Finish the function. */ fn = finish_function (inline_p); + + if (modules_p () + && !inline_p + && TYPE_P (DECL_CONTEXT (fn)) + && (DECL_DECLARED_INLINE_P (fn) + || processing_template_decl)) + set_defining_module (fn); + /* Generate code for it, if necessary. */ expand_or_defer_fn (fn); /* Restore the saved values. */ diff --git c/gcc/cp/parser.h w/gcc/cp/parser.h index ec487ea4252..13c37b21326 100644 --- c/gcc/cp/parser.h +++ w/gcc/cp/parser.h @@ -58,7 +58,8 @@ struct GTY (()) cp_token { deleted. */ bool purged_p : 1; bool tree_check_p : 1; - /* 4 unused bits. */ + bool main_source_p : 1; + /* 3 unused bits. */ /* The location at which this token was found. */ location_t location;