From patchwork Tue Oct 26 23:11:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 46678 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 383963857C58 for ; Tue, 26 Oct 2021 23:12:22 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 383963857C58 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1635289942; bh=STiOsjObGOUguI2zMQ/ecKasAi92GP4n7PZH+YBaDQw=; h=Date:Subject:To:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=FlXNNKbxB0xbaks2xpGQOwd8vzBFMkus8I613Jhcy7ifUa0oe4ZftWwjC2+wU8/CH isdG0QL5Kp1Ez5gflakhgQOBXGWeNwkeCB4XfbMpuVHD159/Z5vw8NJGm3bluwEMt/ ucUskeopGv7GY9SeiagUphQ+BPZP135Y22M/KyDo= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-ed1-x531.google.com (mail-ed1-x531.google.com [IPv6:2a00:1450:4864:20::531]) by sourceware.org (Postfix) with ESMTPS id 903563858C60 for ; Tue, 26 Oct 2021 23:11:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 903563858C60 Received: by mail-ed1-x531.google.com with SMTP id 5so2765044edw.7 for ; Tue, 26 Oct 2021 16:11:51 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=STiOsjObGOUguI2zMQ/ecKasAi92GP4n7PZH+YBaDQw=; b=ffeTGjgwn74Vdd6/sL2Cngnw9DQCGHoyxvj0OXtpjhXmQY9LKUGwx6sypeVcNlbwr4 ufkYYyEeicRVHmjQnaYPR0pxKIDp6Kukr+g8o1zauj9+wj6mTYVozpUVowHgEGxP+OnK 5RVvonGcq9UmqrIIouUmnxth0AKXpVHL2m5+Bsv7CPajal7153zCQ7CSgJGhXcMDsXeL xgGnmO71wgxVgSEVm3fCKoYyzupMzg6jfxSTgIJyj6BLRIllinqYbCLLYKpj0RGLPd1c ZXJ8YlezW5Dq0K0qVbgx6kbnZ0fcDbjK0K8a1O9wRLXO16l3/n9MrVrqOPtTRrneBGkH /9Eg== X-Gm-Message-State: AOAM530FAULebily05JlQPQOa0aFOa6ALGwo4LPFun2pJn9EDL9HecPd idiHcnxivMYtTmNPC7GbAchWVWa6YsZkYFR0uzqDplXrq8Xr1A== X-Google-Smtp-Source: ABdhPJzuF/aTm9yZNBM6Aqgfj5gcQ4HwmuaktmLbeh+RLvzmxEoVpTYBuVn69pKOlmnFlqHwOpZHCEoNFb9ytaXvhy8= X-Received: by 2002:a17:906:69c7:: with SMTP id g7mr2952796ejs.365.1635289909917; Tue, 26 Oct 2021 16:11:49 -0700 (PDT) MIME-Version: 1.0 Date: Tue, 26 Oct 2021 16:11:39 -0700 Message-ID: Subject: Go patch committed: Permit compiler directives in parenthesized groups To: gcc-patches , gofrontend-dev X-Spam-Status: No, score=-9.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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: , X-Patchwork-Original-From: Ian Lance Taylor via Gcc-patches From: Ian Lance Taylor Reply-To: Ian Lance Taylor Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" This patch to the Go frontend permits compiler directives in parenthesized groups. The original compiler directive support was only for //line at the start of a line and for //go: comments before function declarations. When support was added for //go:notinheap for types and //go:embed for variables the code did not adapt to permit spaces before the comment or to permit the comments in var() or type() groups. This change corrects those omissions. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian 4571c4689239eda7567a69b0decea52c5f6ce501 diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index affba73e4bb..e7ff6705563 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -925ace70ac7426c3f8b5c0bfb75aa9601f071de4 +128ea3dce9b8753167f33d0a96bd093a6cbd58b8 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/lex.cc b/gcc/go/gofrontend/lex.cc index dd66c0209a4..d6909b840a8 100644 --- a/gcc/go/gofrontend/lex.cc +++ b/gcc/go/gofrontend/lex.cc @@ -1909,14 +1909,13 @@ Lex::skip_cpp_comment() if (saw_error) return; - // Recognize various magic comments at the start of a line. + // Recognize various magic comments at the start of a line, preceded + // only by spaces or tabs. - if (lineoff != 2) - { - // Not at the start of the line. (lineoff == 2 because of the - // two characters in "//"). + // "- 2" for the "//" at the start of the comment. + for (const char* psp = this->linebuf_; psp < p - 2; psp++) + if (*psp != ' ' && *psp != '\t') return; - } while (pend > p && (pend[-1] == ' ' || pend[-1] == '\t' diff --git a/gcc/go/gofrontend/lex.h b/gcc/go/gofrontend/lex.h index 75c8429b68f..1c4cc5bd2a1 100644 --- a/gcc/go/gofrontend/lex.h +++ b/gcc/go/gofrontend/lex.h @@ -420,6 +420,12 @@ class Lex std::swap(*embeds, this->embeds_); } + // Clear any go:embed patterns seen so far. This is used for + // erroneous cases. + void + clear_embeds() + { this->embeds_.clear(); } + // Return whether the identifier NAME should be exported. NAME is a // mangled name which includes only ASCII characters. static bool diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index e43b5f21448..cc197e5eb35 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -1307,46 +1307,14 @@ void Parse::declaration() { const Token* token = this->peek_token(); - - unsigned int pragmas = this->lex_->get_and_clear_pragmas(); - if (pragmas != 0 - && !token->is_keyword(KEYWORD_FUNC) - && !token->is_keyword(KEYWORD_TYPE)) - go_warning_at(token->location(), 0, - "ignoring magic comment before non-function"); - - std::vector* embeds = NULL; - if (this->lex_->has_embeds()) - { - embeds = new(std::vector); - this->lex_->get_and_clear_embeds(embeds); - - if (!this->gogo_->current_file_imported_embed()) - { - go_error_at(token->location(), - "invalid go:embed: missing import %"); - delete embeds; - embeds = NULL; - } - if (!token->is_keyword(KEYWORD_VAR)) - { - go_error_at(token->location(), "misplaced go:embed directive"); - if (embeds != NULL) - { - delete embeds; - embeds = NULL; - } - } - } - if (token->is_keyword(KEYWORD_CONST)) this->const_decl(); else if (token->is_keyword(KEYWORD_TYPE)) - this->type_decl(pragmas); + this->type_decl(); else if (token->is_keyword(KEYWORD_VAR)) - this->var_decl(embeds); + this->var_decl(); else if (token->is_keyword(KEYWORD_FUNC)) - this->function_decl(pragmas); + this->function_decl(); else { go_error_at(this->location(), "expected declaration"); @@ -1367,8 +1335,7 @@ Parse::declaration_may_start_here() // Decl

= P | "(" [ List

] ")" . void -Parse::decl(void (Parse::*pfn)(unsigned int, std::vector*), - unsigned int pragmas, std::vector* embeds) +Parse::decl(void (Parse::*pfn)()) { if (this->peek_token()->is_eof()) { @@ -1378,15 +1345,18 @@ Parse::decl(void (Parse::*pfn)(unsigned int, std::vector*), } if (!this->peek_token()->is_op(OPERATOR_LPAREN)) - (this->*pfn)(pragmas, embeds); + (this->*pfn)(); else { - if (pragmas != 0) - go_warning_at(this->location(), 0, - "ignoring magic % comment before group"); - if (embeds != NULL) + if (this->lex_->get_and_clear_pragmas() != 0) go_error_at(this->location(), - "ignoring % comment before group"); + "ignoring compiler directive before group"); + if (this->lex_->has_embeds()) + { + this->lex_->clear_embeds(); + go_error_at(this->location(), + "ignoring % comment before group"); + } if (!this->advance_token()->is_op(OPERATOR_RPAREN)) { this->list(pfn, true); @@ -1410,10 +1380,9 @@ Parse::decl(void (Parse::*pfn)(unsigned int, std::vector*), // might follow. This is either a '}' or a ')'. void -Parse::list(void (Parse::*pfn)(unsigned int, std::vector*), - bool follow_is_paren) +Parse::list(void (Parse::*pfn)(), bool follow_is_paren) { - (this->*pfn)(0, NULL); + (this->*pfn)(); Operator follow = follow_is_paren ? OPERATOR_RPAREN : OPERATOR_RCURLY; while (this->peek_token()->is_op(OPERATOR_SEMICOLON) || this->peek_token()->is_op(OPERATOR_COMMA)) @@ -1422,7 +1391,7 @@ Parse::list(void (Parse::*pfn)(unsigned int, std::vector*), go_error_at(this->location(), "unexpected comma"); if (this->advance_token()->is_op(follow)) break; - (this->*pfn)(0, NULL); + (this->*pfn)(); } } @@ -1469,6 +1438,8 @@ Parse::const_decl() void Parse::const_spec(int iota, Type** last_type, Expression_list** last_expr_list) { + this->check_directives(); + Location loc = this->location(); Typed_identifier_list til; this->identifier_list(&til); @@ -1545,18 +1516,21 @@ Parse::const_spec(int iota, Type** last_type, Expression_list** last_expr_list) // TypeDecl = "type" Decl . void -Parse::type_decl(unsigned int pragmas) +Parse::type_decl() { go_assert(this->peek_token()->is_keyword(KEYWORD_TYPE)); this->advance_token(); - this->decl(&Parse::type_spec, pragmas, NULL); + this->decl(&Parse::type_spec); } // TypeSpec = identifier ["="] Type . void -Parse::type_spec(unsigned int pragmas, std::vector*) +Parse::type_spec() { + unsigned int pragmas = this->lex_->get_and_clear_pragmas(); + this->check_directives(); + const Token* token = this->peek_token(); if (!token->is_identifier()) { @@ -1649,23 +1623,34 @@ Parse::type_spec(unsigned int pragmas, std::vector*) // VarDecl = "var" Decl . void -Parse::var_decl(std::vector* embeds) +Parse::var_decl() { go_assert(this->peek_token()->is_keyword(KEYWORD_VAR)); this->advance_token(); - this->decl(&Parse::var_spec, 0, embeds); + this->decl(&Parse::var_spec); } // VarSpec = IdentifierList // ( CompleteType [ "=" ExpressionList ] | "=" ExpressionList ) . void -Parse::var_spec(unsigned int pragmas, std::vector* embeds) +Parse::var_spec() { Location loc = this->location(); - if (pragmas != 0) - go_warning_at(loc, 0, "ignoring magic % comment before var"); + std::vector* embeds = NULL; + if (this->lex_->has_embeds()) + { + if (!this->gogo_->current_file_imported_embed()) + go_error_at(loc, "invalid go:embed: missing import %"); + else + { + embeds = new(std::vector); + this->lex_->get_and_clear_embeds(embeds); + } + } + + this->check_directives(); // Get the variable names. Typed_identifier_list til; @@ -2339,9 +2324,13 @@ Parse::simple_var_decl_or_assignment(const std::string& name, // PRAGMAS is a bitset of magic comments. void -Parse::function_decl(unsigned int pragmas) +Parse::function_decl() { go_assert(this->peek_token()->is_keyword(KEYWORD_FUNC)); + + unsigned int pragmas = this->lex_->get_and_clear_pragmas(); + this->check_directives(); + Location location = this->location(); std::string extern_name = this->lex_->extern_name(); const Token* token = this->advance_token(); @@ -5370,7 +5359,7 @@ Parse::for_stat(Label* label) { go_error_at(this->location(), "var declaration not allowed in for initializer"); - this->var_decl(NULL); + this->var_decl(); } if (token->is_op(OPERATOR_SEMICOLON)) @@ -5815,17 +5804,15 @@ Parse::import_decl() { go_assert(this->peek_token()->is_keyword(KEYWORD_IMPORT)); this->advance_token(); - this->decl(&Parse::import_spec, 0, NULL); + this->decl(&Parse::import_spec); } // ImportSpec = [ "." | PackageName ] PackageFileName . void -Parse::import_spec(unsigned int pragmas, std::vector*) +Parse::import_spec() { - if (pragmas != 0) - go_warning_at(this->location(), 0, - "ignoring magic % comment before import"); + this->check_directives(); const Token* token = this->peek_token(); Location location = token->location(); @@ -5916,6 +5903,23 @@ Parse::program() this->skip_past_error(OPERATOR_INVALID); } } + + this->check_directives(); +} + +// If there are any pending compiler directives, clear them and give +// an error. This is called when directives are not permitted. + +void +Parse::check_directives() +{ + if (this->lex_->get_and_clear_pragmas() != 0) + go_error_at(this->location(), "misplaced compiler directive"); + if (this->lex_->has_embeds()) + { + this->lex_->clear_embeds(); + go_error_at(this->location(), "misplaced go:embed directive"); + } } // Skip forward to a semicolon or OP. OP will normally be diff --git a/gcc/go/gofrontend/parse.h b/gcc/go/gofrontend/parse.h index 2c3c505ffa9..6e300ef800c 100644 --- a/gcc/go/gofrontend/parse.h +++ b/gcc/go/gofrontend/parse.h @@ -181,15 +181,14 @@ class Parse void method_spec(Typed_identifier_list*); void declaration(); bool declaration_may_start_here(); - void decl(void (Parse::*)(unsigned int, std::vector*), - unsigned int pragmas, std::vector* embeds); - void list(void (Parse::*)(unsigned int, std::vector*), bool); + void decl(void (Parse::*)()); + void list(void (Parse::*)(), bool); void const_decl(); void const_spec(int, Type**, Expression_list**); - void type_decl(unsigned int pragmas); - void type_spec(unsigned int pragmas, std::vector*); - void var_decl(std::vector* embeds); - void var_spec(unsigned int pragmas, std::vector*); + void type_decl(); + void type_spec(); + void var_decl(); + void var_spec(); void init_vars(const Typed_identifier_list*, Type*, Expression_list*, bool is_coloneq, std::vector*, Location); bool init_vars_from_call(const Typed_identifier_list*, Type*, Expression*, @@ -210,7 +209,7 @@ class Parse void simple_var_decl_or_assignment(const std::string&, Location, bool may_be_composite_lit, Range_clause*, Type_switch*); - void function_decl(unsigned int pragmas); + void function_decl(); Typed_identifier* receiver(); Expression* operand(bool may_be_sink, bool *is_parenthesized); Expression* enclosing_var_reference(Named_object*, Named_object*, @@ -278,7 +277,10 @@ class Parse void goto_stat(); void package_clause(); void import_decl(); - void import_spec(unsigned int pragmas, std::vector*); + void import_spec(); + + // Check for unused compiler directives. + void check_directives(); // Skip past an error looking for a semicolon or OP. Return true if // all is well, false if we found EOF.