mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 14:59:39 +02:00
gccrs: Collect feature gate error at parse time
Some nightly features change the parser's behavior, it may accepts syntax that should be rejected when the feature is missing. But the complete list of enabled features can only be found once the parsing is complete. We should therefore not emit any error at parse time and instead collect a potential error and emit it later during the feature gating step. gcc/rust/ChangeLog: * checks/errors/feature/rust-feature-gate.cc (FeatureGate::check): Check all parse time errors. * checks/errors/feature/rust-feature-gate.h: Update function prototype with parse time errors. * parse/rust-parse-impl-attribute.hxx: Collect potential gating error with non literal attribute values. Remove error emission. * parse/rust-parse.h: Add a function to gather potential feature gating errors as well as a getter for collected errors. * rust-session-manager.cc (Session::compile_crate): Retrieve potential feature gating errors and check them later during the feature gating step. * util/rust-attributes.cc (check_export_name_attribute): Change attribute checking error emission to prevent errors with macro inputs. gcc/testsuite/ChangeLog: * rust/compile/doc_macro.rs: Enable feature to use a macro within an attribute input. * rust/compile/parse_time_feature_gate.rs: New test. Signed-off-by: Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
This commit is contained in:
committed by
Arthur Cohen
parent
dcd8b112c8
commit
aff1c8aade
@@ -27,8 +27,12 @@
|
||||
namespace Rust {
|
||||
|
||||
void
|
||||
FeatureGate::check (AST::Crate &crate)
|
||||
FeatureGate::check (
|
||||
AST::Crate &crate,
|
||||
std::vector<std::pair<Feature::Name, Error>> &parsing_feature_gate_errors)
|
||||
{
|
||||
for (auto &pair : parsing_feature_gate_errors)
|
||||
gate (pair.first, pair.second.locus, pair.second.message);
|
||||
visit (crate);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,9 @@ public:
|
||||
|
||||
using AST::DefaultASTVisitor::visit;
|
||||
|
||||
void check (AST::Crate &crate);
|
||||
void check (
|
||||
AST::Crate &crate,
|
||||
std::vector<std::pair<Feature::Name, Error>> &parsing_feature_gate_errors);
|
||||
void visit (AST::Crate &crate) override;
|
||||
|
||||
void visit (AST::LifetimeParam &lifetime_param) override;
|
||||
|
||||
@@ -293,6 +293,16 @@ Parser<ManagedTokenSource>::parse_attr_input ()
|
||||
|
||||
t = lexer.peek_token ();
|
||||
|
||||
/* Ensure token is a "literal expression" (literally only a literal
|
||||
* token of any type) */
|
||||
if (!t->is_literal ())
|
||||
{
|
||||
Error error (
|
||||
t->get_locus (),
|
||||
"arbitrary expressions in key-value attributes are unstable");
|
||||
collect_potential_gating_error (
|
||||
Feature::Name::EXTENDED_KEY_VALUE_ATTRIBUTES, std::move (error));
|
||||
}
|
||||
// attempt to parse macro
|
||||
// TODO: macros may/may not be allowed in attributes
|
||||
// this is needed for "#[doc = include_str!(...)]"
|
||||
@@ -308,20 +318,6 @@ Parser<ManagedTokenSource>::parse_attr_input ()
|
||||
new AST::AttrInputMacro (std::move (invoke)));
|
||||
}
|
||||
|
||||
/* Ensure token is a "literal expression" (literally only a literal
|
||||
* token of any type) */
|
||||
if (!t->is_literal ())
|
||||
{
|
||||
Error error (
|
||||
t->get_locus (),
|
||||
"unknown token %qs in attribute body - literal expected",
|
||||
t->get_token_description ());
|
||||
add_error (std::move (error));
|
||||
|
||||
skip_after_end_attribute ();
|
||||
return Parse::Error::AttrInput::make_malformed ();
|
||||
}
|
||||
|
||||
AST::Literal::LitType lit_type = AST::Literal::STRING;
|
||||
// Crappy mapping of token type to literal type
|
||||
switch (t->get_id ())
|
||||
@@ -345,9 +341,14 @@ Parser<ManagedTokenSource>::parse_attr_input ()
|
||||
lit_type = AST::Literal::RAW_STRING;
|
||||
break;
|
||||
case STRING_LITERAL:
|
||||
default:
|
||||
lit_type = AST::Literal::STRING;
|
||||
break; // TODO: raw string? don't eliminate it from lexer?
|
||||
default:
|
||||
rust_sorry_at (t->get_locus (),
|
||||
"Unsupported attribute input, only literals and "
|
||||
"macros are supported for now");
|
||||
skip_after_end_attribute ();
|
||||
return Parse::Error::AttrInput::make_malformed ();
|
||||
}
|
||||
|
||||
// create actual LiteralExpr
|
||||
|
||||
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "rust-diagnostics.h"
|
||||
#include "rust-parse-error.h"
|
||||
#include "rust-parse-utils.h"
|
||||
#include "rust-feature.h"
|
||||
|
||||
#include "expected.h"
|
||||
|
||||
@@ -852,6 +853,17 @@ private:
|
||||
|
||||
void add_error (Error error) { error_table.push_back (std::move (error)); }
|
||||
|
||||
// We don't know the crate's valid feature set since we may not have parsed
|
||||
// all feature declaration attributes yet, some features are not available and
|
||||
// we can't decide at parse time whether we should reject the syntax.
|
||||
//
|
||||
// To fix this we collect the feature gating errors now and will emit the
|
||||
// errors later.
|
||||
void collect_potential_gating_error (Feature::Name feature, Error error)
|
||||
{
|
||||
gating_errors.emplace_back (feature, error);
|
||||
}
|
||||
|
||||
public:
|
||||
// Construct parser with specified "managed" token source.
|
||||
Parser (ManagedTokenSource &tokenSource) : lexer (tokenSource) {}
|
||||
@@ -874,6 +886,12 @@ public:
|
||||
// Get a reference to the list of errors encountered
|
||||
std::vector<Error> &get_errors () { return error_table; }
|
||||
|
||||
std::vector<std::pair<Feature::Name, Error>> &
|
||||
get_potential_feature_gate_errors ()
|
||||
{
|
||||
return gating_errors;
|
||||
}
|
||||
|
||||
const ManagedTokenSource &get_token_source () const { return lexer; }
|
||||
|
||||
const_TokenPtr peek_current_token () { return lexer.peek_token (0); }
|
||||
@@ -884,6 +902,8 @@ private:
|
||||
ManagedTokenSource &lexer;
|
||||
// The error list.
|
||||
std::vector<Error> error_table;
|
||||
|
||||
std::vector<std::pair<Feature::Name, Error>> gating_errors;
|
||||
// The names of inline modules while parsing.
|
||||
std::vector<std::string> inline_module_stack;
|
||||
|
||||
|
||||
@@ -601,6 +601,7 @@ Session::compile_crate (const char *filename)
|
||||
|
||||
// generate crate from parser
|
||||
std::unique_ptr<AST::Crate> ast_crate = parser.parse_crate ();
|
||||
auto &feature_gate_errors = parser.get_potential_feature_gate_errors ();
|
||||
|
||||
// handle crate name
|
||||
handle_crate_name (filename, *ast_crate.get ());
|
||||
@@ -712,7 +713,7 @@ Session::compile_crate (const char *filename)
|
||||
if (last_step == CompileOptions::CompileStep::FeatureGating)
|
||||
return;
|
||||
|
||||
FeatureGate (parsed_crate_features).check (parsed_crate);
|
||||
FeatureGate (parsed_crate_features).check (parsed_crate, feature_gate_errors);
|
||||
|
||||
if (last_step == CompileOptions::CompileStep::NameResolution)
|
||||
return;
|
||||
|
||||
@@ -498,11 +498,38 @@ check_export_name_attribute (const AST::Attribute &attribute)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Attributes::extract_string_literal (attribute))
|
||||
// We don't support the whole extended_key_value_attributes feature, we only
|
||||
// support a subset for macros. We need to emit an error message when the
|
||||
// attribute does not contain a macro or a string literal.
|
||||
if (attribute.has_attr_input ())
|
||||
{
|
||||
rust_error_at (attribute.get_locus (),
|
||||
"attribute must be a string literal");
|
||||
auto &attr_input = attribute.get_attr_input ();
|
||||
switch (attr_input.get_attr_input_type ())
|
||||
{
|
||||
case AST::AttrInput::AttrInputType::LITERAL:
|
||||
{
|
||||
auto &literal_expr
|
||||
= static_cast<AST::AttrInputLiteral &> (attr_input)
|
||||
.get_literal ();
|
||||
auto lit_type = literal_expr.get_lit_type ();
|
||||
switch (lit_type)
|
||||
{
|
||||
case AST::Literal::LitType::STRING:
|
||||
case AST::Literal::LitType::RAW_STRING:
|
||||
case AST::Literal::LitType::BYTE_STRING:
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AST::AttrInput::AttrInputType::MACRO:
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
rust_error_at (attribute.get_locus (), "attribute must be a string literal");
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
|
||||
#![feature(extended_key_value_attributes)]
|
||||
#![doc = concat!("AB")]
|
||||
|
||||
6
gcc/testsuite/rust/compile/parse_time_feature_gate.rs
Normal file
6
gcc/testsuite/rust/compile/parse_time_feature_gate.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
|
||||
// { dg-error "arbitrary expressions in key-value attributes are unstable" "" { target *-*-* } .+1 }
|
||||
#[export_name = concat!(stringify!(non), stringify!(literal))]
|
||||
pub extern "C" fn attribute_test_function() {}
|
||||
Reference in New Issue
Block a user