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);
}
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;
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!(...)]"
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 ())
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
#include "rust-diagnostics.h"
#include "rust-parse-error.h"
#include "rust-parse-utils.h"
+#include "rust-feature.h"
#include "expected.h"
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) {}
// 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); }
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;
// 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 ());
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;
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
#![feature(no_core)]
#![no_core]
-
+#![feature(extended_key_value_attributes)]
#![doc = concat!("AB")]
--- /dev/null
+#![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() {}