Skip to content

Commit d6e2638

Browse files
committed
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>
1 parent d8e2f47 commit d6e2638

File tree

8 files changed

+84
-22
lines changed

8 files changed

+84
-22
lines changed

gcc/rust/checks/errors/feature/rust-feature-gate.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,12 @@
2727
namespace Rust {
2828

2929
void
30-
FeatureGate::check (AST::Crate &crate)
30+
FeatureGate::check (
31+
AST::Crate &crate,
32+
std::vector<std::pair<Feature::Name, Error>> &parsing_feature_gate_errors)
3133
{
34+
for (auto &pair : parsing_feature_gate_errors)
35+
gate (pair.first, pair.second.locus, pair.second.message);
3236
visit (crate);
3337
}
3438

gcc/rust/checks/errors/feature/rust-feature-gate.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ class FeatureGate : public AST::DefaultASTVisitor
3232

3333
using AST::DefaultASTVisitor::visit;
3434

35-
void check (AST::Crate &crate);
35+
void check (
36+
AST::Crate &crate,
37+
std::vector<std::pair<Feature::Name, Error>> &parsing_feature_gate_errors);
3638
void visit (AST::Crate &crate) override;
3739

3840
void visit (AST::LifetimeParam &lifetime_param) override;

gcc/rust/parse/rust-parse-impl-attribute.hxx

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,17 @@ Parser<ManagedTokenSource>::parse_attr_input ()
293293

294294
t = lexer.peek_token ();
295295

296+
/* Ensure token is a "literal expression" (literally only a literal
297+
* token of any type) */
298+
if (!t->is_literal ())
299+
{
300+
Error error (
301+
t->get_locus (),
302+
"arbitrary expressions in key-value attributes are unstable",
303+
t->get_token_description ());
304+
collect_potential_gating_error (
305+
Feature::Name::EXTENDED_KEY_VALUE_ATTRIBUTES, std::move (error));
306+
}
296307
// attempt to parse macro
297308
// TODO: macros may/may not be allowed in attributes
298309
// this is needed for "#[doc = include_str!(...)]"
@@ -308,20 +319,6 @@ Parser<ManagedTokenSource>::parse_attr_input ()
308319
new AST::AttrInputMacro (std::move (invoke)));
309320
}
310321

311-
/* Ensure token is a "literal expression" (literally only a literal
312-
* token of any type) */
313-
if (!t->is_literal ())
314-
{
315-
Error error (
316-
t->get_locus (),
317-
"unknown token %qs in attribute body - literal expected",
318-
t->get_token_description ());
319-
add_error (std::move (error));
320-
321-
skip_after_end_attribute ();
322-
return Parse::Error::AttrInput::make_malformed ();
323-
}
324-
325322
AST::Literal::LitType lit_type = AST::Literal::STRING;
326323
// Crappy mapping of token type to literal type
327324
switch (t->get_id ())
@@ -345,9 +342,14 @@ Parser<ManagedTokenSource>::parse_attr_input ()
345342
lit_type = AST::Literal::RAW_STRING;
346343
break;
347344
case STRING_LITERAL:
348-
default:
349345
lit_type = AST::Literal::STRING;
350346
break; // TODO: raw string? don't eliminate it from lexer?
347+
default:
348+
rust_sorry_at (t->get_locus (),
349+
"Unsupported attribute input, only literals and "
350+
"macros are supported for now");
351+
skip_after_end_attribute ();
352+
return Parse::Error::AttrInput::make_malformed ();
351353
}
352354

353355
// create actual LiteralExpr

gcc/rust/parse/rust-parse.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
2424
#include "rust-diagnostics.h"
2525
#include "rust-parse-error.h"
2626
#include "rust-parse-utils.h"
27+
#include "rust-feature.h"
2728

2829
#include "expected.h"
2930

@@ -852,6 +853,17 @@ template <typename ManagedTokenSource> class Parser
852853

853854
void add_error (Error error) { error_table.push_back (std::move (error)); }
854855

856+
// We don't know the crate's valid feature set since we may not have parsed
857+
// all feature declaration attributes yet, some features are not available and
858+
// we can't decide at parse time whether we should reject the syntax.
859+
//
860+
// To fix this we collect the feature gating errors now and will emit the
861+
// errors later.
862+
void collect_potential_gating_error (Feature::Name feature, Error error)
863+
{
864+
gating_errors.emplace_back (feature, error);
865+
}
866+
855867
public:
856868
// Construct parser with specified "managed" token source.
857869
Parser (ManagedTokenSource &tokenSource) : lexer (tokenSource) {}
@@ -874,6 +886,12 @@ template <typename ManagedTokenSource> class Parser
874886
// Get a reference to the list of errors encountered
875887
std::vector<Error> &get_errors () { return error_table; }
876888

889+
std::vector<std::pair<Feature::Name, Error>> &
890+
get_potential_feature_gate_errors ()
891+
{
892+
return gating_errors;
893+
}
894+
877895
const ManagedTokenSource &get_token_source () const { return lexer; }
878896

879897
const_TokenPtr peek_current_token () { return lexer.peek_token (0); }
@@ -884,6 +902,8 @@ template <typename ManagedTokenSource> class Parser
884902
ManagedTokenSource &lexer;
885903
// The error list.
886904
std::vector<Error> error_table;
905+
906+
std::vector<std::pair<Feature::Name, Error>> gating_errors;
887907
// The names of inline modules while parsing.
888908
std::vector<std::string> inline_module_stack;
889909

gcc/rust/rust-session-manager.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,7 @@ Session::compile_crate (const char *filename)
601601

602602
// generate crate from parser
603603
std::unique_ptr<AST::Crate> ast_crate = parser.parse_crate ();
604+
auto &feature_gate_errors = parser.get_potential_feature_gate_errors ();
604605

605606
// handle crate name
606607
handle_crate_name (filename, *ast_crate.get ());
@@ -712,7 +713,7 @@ Session::compile_crate (const char *filename)
712713
if (last_step == CompileOptions::CompileStep::FeatureGating)
713714
return;
714715

715-
FeatureGate (parsed_crate_features).check (parsed_crate);
716+
FeatureGate (parsed_crate_features).check (parsed_crate, feature_gate_errors);
716717

717718
if (last_step == CompileOptions::CompileStep::NameResolution)
718719
return;

gcc/rust/util/rust-attributes.cc

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -498,11 +498,38 @@ check_export_name_attribute (const AST::Attribute &attribute)
498498
return;
499499
}
500500

501-
if (!Attributes::extract_string_literal (attribute))
501+
// We don't support the whole extended_key_value_attributes feature, we only
502+
// support a subset for macros. We need to emit an error message when the
503+
// attribute does not contain a macro or a string literal.
504+
if (attribute.has_attr_input ())
502505
{
503-
rust_error_at (attribute.get_locus (),
504-
"attribute must be a string literal");
506+
auto &attr_input = attribute.get_attr_input ();
507+
switch (attr_input.get_attr_input_type ())
508+
{
509+
case AST::AttrInput::AttrInputType::LITERAL:
510+
{
511+
auto &literal_expr
512+
= static_cast<AST::AttrInputLiteral &> (attr_input)
513+
.get_literal ();
514+
auto lit_type = literal_expr.get_lit_type ();
515+
switch (lit_type)
516+
{
517+
case AST::Literal::LitType::STRING:
518+
case AST::Literal::LitType::RAW_STRING:
519+
case AST::Literal::LitType::BYTE_STRING:
520+
return;
521+
default:
522+
break;
523+
}
524+
break;
525+
}
526+
case AST::AttrInput::AttrInputType::MACRO:
527+
return;
528+
default:
529+
break;
530+
}
505531
}
532+
rust_error_at (attribute.get_locus (), "attribute must be a string literal");
506533
}
507534

508535
static void
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#![feature(no_core)]
22
#![no_core]
3-
3+
#![feature(extended_key_value_attributes)]
44
#![doc = concat!("AB")]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#![feature(no_core)]
2+
#![no_core]
3+
4+
// { dg-error "arbitrary expressions in key-value attributes are unstable" "" { target *-*-* } .+1 }
5+
#[export_name = concat!(stringify!(non), stringify!(literal))]
6+
pub extern "C" fn attribute_test_function() {}

0 commit comments

Comments
 (0)