diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 14dedcb0c3478..fcfa860f25ef3 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -556,8 +556,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { ProjectionElem::Field(..) | ProjectionElem::Index(_) => { - if this.mode != Mode::Fn && - this.qualif.intersects(Qualif::STATIC) { + if this.mode == Mode::Fn { + let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx); + if let Some(def) = base_ty.ty_adt_def() { + if def.is_union() { + this.not_const(); + } + } + } else if this.qualif.intersects(Qualif::STATIC) { span_err!(this.tcx.sess, this.span, E0494, "cannot refer to the interior of another \ static, use a constant instead"); diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index d4fa47c5b48b9..3a05986a1d4ee 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -424,9 +424,16 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } - hir::ExprBlock(_) | + hir::ExprField(ref expr, _) => { + if let Some(def) = v.tables.expr_ty(expr).ty_adt_def() { + if def.is_union() { + v.promotable = false + } + } + } + + hir::ExprBlock(..) | hir::ExprIndex(..) | - hir::ExprField(..) | hir::ExprArray(_) | hir::ExprType(..) | hir::ExprTup(..) => {} diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index ace9904e0c021..c70f57492026b 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -17,7 +17,7 @@ pub use self::IntType::*; use ast; use ast::{AttrId, Attribute, Name, Ident, Path, PathSegment}; use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; -use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind}; +use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind, GenericParam}; use codemap::{BytePos, Spanned, respan, dummy_spanned}; use syntax_pos::Span; use errors::Handler; @@ -1438,6 +1438,22 @@ impl HasAttrs for Stmt { } } +impl HasAttrs for GenericParam { + fn attrs(&self) -> &[ast::Attribute] { + match self { + GenericParam::Lifetime(lifetime) => lifetime.attrs(), + GenericParam::Type(ty) => ty.attrs(), + } + } + + fn map_attrs) -> Vec>(self, f: F) -> Self { + match self { + GenericParam::Lifetime(lifetime) => GenericParam::Lifetime(lifetime.map_attrs(f)), + GenericParam::Type(ty) => GenericParam::Type(ty.map_attrs(f)), + } + } +} + macro_rules! derive_has_attrs { ($($ty:path),*) => { $( impl HasAttrs for $ty { @@ -1457,5 +1473,5 @@ macro_rules! derive_has_attrs { derive_has_attrs! { Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm, - ast::Field, ast::FieldPat, ast::Variant_ + ast::Field, ast::FieldPat, ast::Variant_, ast::LifetimeDef, ast::TyParam } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 36911683a0e77..3364378913952 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -278,6 +278,22 @@ impl<'a> StripUnconfigured<'a> { pattern }) } + + // deny #[cfg] on generic parameters until we decide what to do with it. + // see issue #51279. + pub fn disallow_cfg_on_generic_param(&mut self, param: &ast::GenericParam) { + for attr in param.attrs() { + let offending_attr = if attr.check_name("cfg") { + "cfg" + } else if attr.check_name("cfg_attr") { + "cfg_attr" + } else { + continue; + }; + let msg = format!("#[{}] cannot be applied on a generic parameter", offending_attr); + self.sess.span_diagnostic.span_err(attr.span, &msg); + } + } } impl<'a> fold::Folder for StripUnconfigured<'a> { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 584b9455a93ad..8fee4881cca5d 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1350,6 +1350,11 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } } + fn fold_generic_param(&mut self, param: ast::GenericParam) -> ast::GenericParam { + self.cfg.disallow_cfg_on_generic_param(¶m); + noop_fold_generic_param(param, self) + } + fn fold_attribute(&mut self, at: ast::Attribute) -> Option { // turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename", // contents="file contents")]` attributes diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index 77c6afa1c64a6..01b971976a763 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -386,26 +386,72 @@ where { // We basically look at two token trees here, denoted as #1 and #2 below let span = match parse_kleene_op(input, span) { - // #1 is any KleeneOp (`?`) - Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => { - if !features.macro_at_most_once_rep - && !attr::contains_name(attrs, "allow_internal_unstable") - { - let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; - emit_feature_err( - sess, - "macro_at_most_once_rep", - span, - GateIssue::Language, - explain, - ); + // #1 is a `+` or `*` KleeneOp + // + // `?` is ambiguous: it could be a separator or a Kleene::ZeroOrOne, so we need to look + // ahead one more token to be sure. + Ok(Ok(op)) if op != KleeneOp::ZeroOrOne => return (None, op), + + // #1 is `?` token, but it could be a Kleene::ZeroOrOne without a separator or it could + // be a `?` separator followed by any Kleene operator. We need to look ahead 1 token to + // find out which. + Ok(Ok(op)) => { + assert_eq!(op, KleeneOp::ZeroOrOne); + + // Lookahead at #2. If it is a KleenOp, then #1 is a separator. + let is_1_sep = if let Some(&tokenstream::TokenTree::Token(_, ref tok2)) = input.peek() { + kleene_op(tok2).is_some() + } else { + false + }; + + if is_1_sep { + // #1 is a separator and #2 should be a KleepeOp::* + // (N.B. We need to advance the input iterator.) + match parse_kleene_op(input, span) { + // #2 is a KleeneOp (this is the only valid option) :) + Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => { + if !features.macro_at_most_once_rep + && !attr::contains_name(attrs, "allow_internal_unstable") + { + let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; + emit_feature_err( + sess, + "macro_at_most_once_rep", + span, + GateIssue::Language, + explain, + ); + } + return (Some(token::Question), op); + } + Ok(Ok(op)) => return (Some(token::Question), op), + + // #2 is a random token (this is an error) :( + Ok(Err((_, span))) => span, + + // #2 is not even a token at all :( + Err(span) => span, + } + } else { + if !features.macro_at_most_once_rep + && !attr::contains_name(attrs, "allow_internal_unstable") + { + let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; + emit_feature_err( + sess, + "macro_at_most_once_rep", + span, + GateIssue::Language, + explain, + ); + } + + // #2 is a random tree and #1 is KleeneOp::ZeroOrOne + return (None, op); } - return (None, op); } - // #1 is any KleeneOp (`+`, `*`) - Ok(Ok(op)) => return (None, op), - // #1 is a separator followed by #2, a KleeneOp Ok(Err((tok, span))) => match parse_kleene_op(input, span) { // #2 is a KleeneOp :D @@ -421,11 +467,8 @@ where GateIssue::Language, explain, ); - } else { - sess.span_diagnostic - .span_err(span, "`?` macro repetition does not allow a separator"); } - return (None, op); + return (Some(tok), op); } Ok(Ok(op)) => return (Some(tok), op), @@ -440,7 +483,9 @@ where Err(span) => span, }; - if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") { + if !features.macro_at_most_once_rep + && !attr::contains_name(attrs, "allow_internal_unstable") + { sess.span_diagnostic .span_err(span, "expected one of: `*`, `+`, or `?`"); } else { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9838a11372bd4..7f8c361525f16 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -586,7 +586,7 @@ declare_features! ( // allow `'_` placeholder lifetimes (accepted, underscore_lifetimes, "1.26.0", Some(44524), None), // Allows attributes on lifetime/type formal parameters in generics (RFC 1327) - (accepted, generic_param_attrs, "1.26.0", Some(48848), None), + (accepted, generic_param_attrs, "1.27.0", Some(48848), None), // Allows cfg(target_feature = "..."). (accepted, cfg_target_feature, "1.27.0", Some(29717), None), // Allows #[target_feature(...)] diff --git a/src/test/run-pass/ctfe/union-ice.rs b/src/test/run-pass/ctfe/union-ice.rs deleted file mode 100644 index f83f49f298b90..0000000000000 --- a/src/test/run-pass/ctfe/union-ice.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(const_fn)] - -type Field1 = i32; -type Field2 = f32; -type Field3 = i64; - -union DummyUnion { - field1: Field1, - field2: Field2, - field3: Field3, -} - -const FLOAT1_AS_I32: i32 = 1065353216; -const UNION: DummyUnion = DummyUnion { field1: FLOAT1_AS_I32 }; - -const fn read_field1() -> Field1 { - const FIELD1: Field1 = unsafe { UNION.field1 }; - FIELD1 -} - -const fn read_field2() -> Field2 { - const FIELD2: Field2 = unsafe { UNION.field2 }; - FIELD2 -} - -const fn read_field3() -> Field3 { - const FIELD3: Field3 = unsafe { UNION.field3 }; - FIELD3 -} - -fn main() { - assert_eq!(read_field1(), FLOAT1_AS_I32); - assert_eq!(read_field2(), 1.0); - assert_eq!(read_field3(), unsafe { UNION.field3 }); -} diff --git a/src/test/run-pass/macro-at-most-once-rep.rs b/src/test/run-pass/macro-at-most-once-rep.rs index c08effe549328..b7e942f938321 100644 --- a/src/test/run-pass/macro-at-most-once-rep.rs +++ b/src/test/run-pass/macro-at-most-once-rep.rs @@ -32,13 +32,25 @@ macro_rules! foo { } } } +macro_rules! baz { + ($($a:ident),? ; $num:expr) => { { // comma separator is meaningless for `?` + let mut x = 0; + + $( + x += $a; + )? + + assert_eq!(x, $num); + } } +} + macro_rules! barplus { ($($a:ident)?+ ; $num:expr) => { { let mut x = 0; $( x += $a; - )? + )+ assert_eq!(x, $num); } } @@ -50,7 +62,7 @@ macro_rules! barstar { $( x += $a; - )? + )* assert_eq!(x, $num); } } @@ -62,10 +74,15 @@ pub fn main() { // accept 0 or 1 repetitions foo!( ; 0); foo!(a ; 1); + baz!( ; 0); + baz!(a ; 1); // Make sure using ? as a separator works as before - barplus!(+ ; 0); - barplus!(a + ; 1); - barstar!(* ; 0); - barstar!(a * ; 1); + barplus!(a ; 1); + barplus!(a?a ; 2); + barplus!(a?a?a ; 3); + barstar!( ; 0); + barstar!(a ; 1); + barstar!(a?a ; 2); + barstar!(a?a?a ; 3); } diff --git a/src/test/run-pass/union/union-const-eval-field.rs b/src/test/run-pass/union/union-const-eval-field.rs index f83f49f298b90..a380b01dcc13f 100644 --- a/src/test/run-pass/union/union-const-eval-field.rs +++ b/src/test/run-pass/union/union-const-eval-field.rs @@ -10,7 +10,7 @@ #![feature(const_fn)] -type Field1 = i32; +type Field1 = (i32, u32); type Field2 = f32; type Field3 = i64; @@ -21,7 +21,7 @@ union DummyUnion { } const FLOAT1_AS_I32: i32 = 1065353216; -const UNION: DummyUnion = DummyUnion { field1: FLOAT1_AS_I32 }; +const UNION: DummyUnion = DummyUnion { field1: (FLOAT1_AS_I32, 0) }; const fn read_field1() -> Field1 { const FIELD1: Field1 = unsafe { UNION.field1 }; @@ -39,7 +39,15 @@ const fn read_field3() -> Field3 { } fn main() { - assert_eq!(read_field1(), FLOAT1_AS_I32); + let foo = FLOAT1_AS_I32; + assert_eq!(read_field1().0, foo); + assert_eq!(read_field1().0, FLOAT1_AS_I32); + + let foo = 1.0; + assert_eq!(read_field2(), foo); assert_eq!(read_field2(), 1.0); + assert_eq!(read_field3(), unsafe { UNION.field3 }); + let foo = unsafe { UNION.field3 }; + assert_eq!(read_field3(), foo); } diff --git a/src/test/ui/const-eval/union_promotion.rs b/src/test/ui/const-eval/union_promotion.rs new file mode 100644 index 0000000000000..714d7a4fc8b27 --- /dev/null +++ b/src/test/ui/const-eval/union_promotion.rs @@ -0,0 +1,22 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(const_err)] + +union Foo { + a: &'static u32, + b: usize, +} + +fn main() { + let x: &'static bool = &unsafe { //~ borrowed value does not live long enough + Foo { a: &1 }.b == Foo { a: &2 }.b + }; +} diff --git a/src/test/ui/const-eval/union_promotion.stderr b/src/test/ui/const-eval/union_promotion.stderr new file mode 100644 index 0000000000000..b4aa91f2de723 --- /dev/null +++ b/src/test/ui/const-eval/union_promotion.stderr @@ -0,0 +1,16 @@ +error[E0597]: borrowed value does not live long enough + --> $DIR/union_promotion.rs:19:29 + | +LL | let x: &'static bool = &unsafe { //~ borrowed value does not live long enough + | _____________________________^ +LL | | Foo { a: &1 }.b == Foo { a: &2 }.b +LL | | }; + | |_____^ temporary value does not live long enough +LL | } + | - temporary value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issue-51279.rs b/src/test/ui/issue-51279.rs new file mode 100644 index 0000000000000..4639d73e44d3d --- /dev/null +++ b/src/test/ui/issue-51279.rs @@ -0,0 +1,34 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct X<#[cfg(none)] 'a, #[cfg(none)] T>(&'a T); +//~^ ERROR #[cfg] cannot be applied on a generic parameter +//~^^ ERROR #[cfg] cannot be applied on a generic parameter + +impl<#[cfg(none)] 'a, #[cfg(none)] T> X<'a, T> {} +//~^ ERROR #[cfg] cannot be applied on a generic parameter +//~^^ ERROR #[cfg] cannot be applied on a generic parameter + +pub fn f<#[cfg(none)] 'a, #[cfg(none)] T>(_: &'a T) {} +//~^ ERROR #[cfg] cannot be applied on a generic parameter +//~^^ ERROR #[cfg] cannot be applied on a generic parameter + +#[cfg(none)] +pub struct Y<#[cfg(none)] T>(T); // shouldn't care when the entire item is stripped out + +struct M(*const T); + +unsafe impl<#[cfg_attr(none, may_dangle)] T> Drop for M { + //~^ ERROR #[cfg_attr] cannot be applied on a generic parameter + fn drop(&mut self) {} +} + +type Z<#[ignored] 'a, #[cfg(none)] T> = X<'a, T>; +//~^ ERROR #[cfg] cannot be applied on a generic parameter diff --git a/src/test/ui/issue-51279.stderr b/src/test/ui/issue-51279.stderr new file mode 100644 index 0000000000000..38d5a5acc50fe --- /dev/null +++ b/src/test/ui/issue-51279.stderr @@ -0,0 +1,50 @@ +error: #[cfg] cannot be applied on a generic parameter + --> $DIR/issue-51279.rs:11:14 + | +LL | pub struct X<#[cfg(none)] 'a, #[cfg(none)] T>(&'a T); + | ^^^^^^^^^^^^ + +error: #[cfg] cannot be applied on a generic parameter + --> $DIR/issue-51279.rs:11:31 + | +LL | pub struct X<#[cfg(none)] 'a, #[cfg(none)] T>(&'a T); + | ^^^^^^^^^^^^ + +error: #[cfg] cannot be applied on a generic parameter + --> $DIR/issue-51279.rs:15:6 + | +LL | impl<#[cfg(none)] 'a, #[cfg(none)] T> X<'a, T> {} + | ^^^^^^^^^^^^ + +error: #[cfg] cannot be applied on a generic parameter + --> $DIR/issue-51279.rs:15:23 + | +LL | impl<#[cfg(none)] 'a, #[cfg(none)] T> X<'a, T> {} + | ^^^^^^^^^^^^ + +error: #[cfg] cannot be applied on a generic parameter + --> $DIR/issue-51279.rs:19:10 + | +LL | pub fn f<#[cfg(none)] 'a, #[cfg(none)] T>(_: &'a T) {} + | ^^^^^^^^^^^^ + +error: #[cfg] cannot be applied on a generic parameter + --> $DIR/issue-51279.rs:19:27 + | +LL | pub fn f<#[cfg(none)] 'a, #[cfg(none)] T>(_: &'a T) {} + | ^^^^^^^^^^^^ + +error: #[cfg_attr] cannot be applied on a generic parameter + --> $DIR/issue-51279.rs:28:13 + | +LL | unsafe impl<#[cfg_attr(none, may_dangle)] T> Drop for M { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: #[cfg] cannot be applied on a generic parameter + --> $DIR/issue-51279.rs:33:23 + | +LL | type Z<#[ignored] 'a, #[cfg(none)] T> = X<'a, T>; + | ^^^^^^^^^^^^ + +error: aborting due to 8 previous errors + diff --git a/src/test/ui/macros/macro-at-most-once-rep-ambig.rs b/src/test/ui/macros/macro-at-most-once-rep-ambig.rs index e25c3ccfcd980..a5660f8b41f8d 100644 --- a/src/test/ui/macros/macro-at-most-once-rep-ambig.rs +++ b/src/test/ui/macros/macro-at-most-once-rep-ambig.rs @@ -8,26 +8,30 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Tests the behavior of various Kleene operators in macros with respect to `?` terminals. In -// particular, `?` in the position of a separator and of a Kleene operator is tested. +// The logic for parsing Kleene operators in macros has a special case to disambiguate `?`. +// Specifically, `$(pat)?` is the ZeroOrOne operator whereas `$(pat)?+` or `$(pat)?*` are the +// ZeroOrMore and OneOrMore operators using `?` as a separator. These tests are intended to +// exercise that logic in the macro parser. +// +// Moreover, we also throw in some tests for using a separator with `?`, which is meaningless but +// included for consistency with `+` and `*`. +// +// This test focuses on error cases. #![feature(macro_at_most_once_rep)] -// should match `` and `a` macro_rules! foo { ($(a)?) => {} } macro_rules! baz { - ($(a),?) => {} //~ ERROR `?` macro repetition does not allow a separator + ($(a),?) => {} // comma separator is meaningless for `?` } -// should match `+` and `a+` macro_rules! barplus { ($(a)?+) => {} } -// should match `*` and `a*` macro_rules! barstar { ($(a)?*) => {} } @@ -36,14 +40,14 @@ pub fn main() { foo!(a?a?a); //~ ERROR no rules expected the token `?` foo!(a?a); //~ ERROR no rules expected the token `?` foo!(a?); //~ ERROR no rules expected the token `?` + baz!(a?a?a); //~ ERROR no rules expected the token `?` + baz!(a?a); //~ ERROR no rules expected the token `?` + baz!(a?); //~ ERROR no rules expected the token `?` + baz!(a,); //~ ERROR unexpected end of macro invocation + baz!(a?a?a,); //~ ERROR no rules expected the token `?` + baz!(a?a,); //~ ERROR no rules expected the token `?` + baz!(a?,); //~ ERROR no rules expected the token `?` barplus!(); //~ ERROR unexpected end of macro invocation - barstar!(); //~ ERROR unexpected end of macro invocation - barplus!(a?); //~ ERROR no rules expected the token `?` - barplus!(a); //~ ERROR unexpected end of macro invocation - barstar!(a?); //~ ERROR no rules expected the token `?` - barstar!(a); //~ ERROR unexpected end of macro invocation - barplus!(+); // ok - barstar!(*); // ok - barplus!(a+); // ok - barstar!(a*); // ok + barplus!(a?); //~ ERROR unexpected end of macro invocation + barstar!(a?); //~ ERROR unexpected end of macro invocation } diff --git a/src/test/ui/macros/macro-at-most-once-rep-ambig.stderr b/src/test/ui/macros/macro-at-most-once-rep-ambig.stderr index cb1e360471cc8..d382082a57585 100644 --- a/src/test/ui/macros/macro-at-most-once-rep-ambig.stderr +++ b/src/test/ui/macros/macro-at-most-once-rep-ambig.stderr @@ -1,62 +1,80 @@ -error: `?` macro repetition does not allow a separator - --> $DIR/macro-at-most-once-rep-ambig.rs:22:10 - | -LL | ($(a),?) => {} //~ ERROR `?` macro repetition does not allow a separator - | ^ - error: no rules expected the token `?` - --> $DIR/macro-at-most-once-rep-ambig.rs:36:11 + --> $DIR/macro-at-most-once-rep-ambig.rs:40:11 | LL | foo!(a?a?a); //~ ERROR no rules expected the token `?` | ^ error: no rules expected the token `?` - --> $DIR/macro-at-most-once-rep-ambig.rs:37:11 + --> $DIR/macro-at-most-once-rep-ambig.rs:41:11 | LL | foo!(a?a); //~ ERROR no rules expected the token `?` | ^ error: no rules expected the token `?` - --> $DIR/macro-at-most-once-rep-ambig.rs:38:11 + --> $DIR/macro-at-most-once-rep-ambig.rs:42:11 | LL | foo!(a?); //~ ERROR no rules expected the token `?` | ^ -error: unexpected end of macro invocation - --> $DIR/macro-at-most-once-rep-ambig.rs:39:5 +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-ambig.rs:43:11 | -LL | barplus!(); //~ ERROR unexpected end of macro invocation - | ^^^^^^^^^^^ +LL | baz!(a?a?a); //~ ERROR no rules expected the token `?` + | ^ -error: unexpected end of macro invocation - --> $DIR/macro-at-most-once-rep-ambig.rs:40:5 +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-ambig.rs:44:11 | -LL | barstar!(); //~ ERROR unexpected end of macro invocation - | ^^^^^^^^^^^ +LL | baz!(a?a); //~ ERROR no rules expected the token `?` + | ^ error: no rules expected the token `?` - --> $DIR/macro-at-most-once-rep-ambig.rs:41:15 + --> $DIR/macro-at-most-once-rep-ambig.rs:45:11 | -LL | barplus!(a?); //~ ERROR no rules expected the token `?` - | ^ +LL | baz!(a?); //~ ERROR no rules expected the token `?` + | ^ error: unexpected end of macro invocation - --> $DIR/macro-at-most-once-rep-ambig.rs:42:14 + --> $DIR/macro-at-most-once-rep-ambig.rs:46:11 + | +LL | baz!(a,); //~ ERROR unexpected end of macro invocation + | ^ + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-ambig.rs:47:11 + | +LL | baz!(a?a?a,); //~ ERROR no rules expected the token `?` + | ^ + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-ambig.rs:48:11 | -LL | barplus!(a); //~ ERROR unexpected end of macro invocation - | ^ +LL | baz!(a?a,); //~ ERROR no rules expected the token `?` + | ^ error: no rules expected the token `?` - --> $DIR/macro-at-most-once-rep-ambig.rs:43:15 + --> $DIR/macro-at-most-once-rep-ambig.rs:49:11 + | +LL | baz!(a?,); //~ ERROR no rules expected the token `?` + | ^ + +error: unexpected end of macro invocation + --> $DIR/macro-at-most-once-rep-ambig.rs:50:5 + | +LL | barplus!(); //~ ERROR unexpected end of macro invocation + | ^^^^^^^^^^^ + +error: unexpected end of macro invocation + --> $DIR/macro-at-most-once-rep-ambig.rs:51:15 | -LL | barstar!(a?); //~ ERROR no rules expected the token `?` +LL | barplus!(a?); //~ ERROR unexpected end of macro invocation | ^ error: unexpected end of macro invocation - --> $DIR/macro-at-most-once-rep-ambig.rs:44:14 + --> $DIR/macro-at-most-once-rep-ambig.rs:52:15 | -LL | barstar!(a); //~ ERROR unexpected end of macro invocation - | ^ +LL | barstar!(a?); //~ ERROR unexpected end of macro invocation + | ^ -error: aborting due to 10 previous errors +error: aborting due to 13 previous errors