diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 1f5a6d79141..6cb3161382a 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -21,7 +21,7 @@ use syntax::visit::{self, Visitor}; use syntax::{span_err, struct_span_err, walk_list}; use syntax_ext::proc_macro_decls::is_proc_macro_attr; use syntax_pos::{Span, MultiSpan}; -use errors::Applicability; +use errors::{Applicability, FatalError}; use log::debug; #[derive(Copy, Clone, Debug)] @@ -368,6 +368,8 @@ fn validate_generics_order<'a>( let mut max_param: Option = None; let mut out_of_order = FxHashMap::default(); let mut param_idents = vec![]; + let mut found_type = false; + let mut found_const = false; for (kind, bounds, span, ident) in generics { if let Some(ident) = ident { @@ -381,6 +383,11 @@ fn validate_generics_order<'a>( } Some(_) | None => *max_param = Some(kind), }; + match kind { + ParamKindOrd::Type => found_type = true, + ParamKindOrd::Const => found_const = true, + _ => {} + } } let mut ordered_params = "<".to_string(); @@ -408,8 +415,8 @@ fn validate_generics_order<'a>( GenericPosition::Arg => "argument", }; - for (param_ord, (max_param, spans)) in out_of_order { - let mut err = handler.struct_span_err(spans, + for (param_ord, (max_param, spans)) in &out_of_order { + let mut err = handler.struct_span_err(spans.clone(), &format!( "{} {pos}s must be declared prior to {} {pos}s", param_ord, @@ -430,6 +437,13 @@ fn validate_generics_order<'a>( } err.emit(); } + + // FIXME(const_generics): we shouldn't have to abort here at all, but we currently get ICEs + // if we don't. Const parameters and type parameters can currently conflict if they + // are out-of-order. + if !out_of_order.is_empty() && found_type && found_const { + FatalError.raise(); + } } impl<'a> Visitor<'a> for AstValidator<'a> { diff --git a/src/test/ui/const-generics/const-param-before-other-params.rs b/src/test/ui/const-generics/const-param-before-other-params.rs index 188b5dce31e..2c81681b85e 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.rs +++ b/src/test/ui/const-generics/const-param-before-other-params.rs @@ -1,12 +1,12 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash -fn foo(_: &T) { - //~^ ERROR type parameters must be declared prior to const parameters -} - fn bar(_: &'a ()) { //~^ ERROR lifetime parameters must be declared prior to const parameters } +fn foo(_: &T) { + //~^ ERROR type parameters must be declared prior to const parameters +} + fn main() {} diff --git a/src/test/ui/const-generics/const-param-before-other-params.stderr b/src/test/ui/const-generics/const-param-before-other-params.stderr index 78f129e79ea..33f981d1eba 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.stderr +++ b/src/test/ui/const-generics/const-param-before-other-params.stderr @@ -4,17 +4,17 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ -error: type parameters must be declared prior to const parameters - --> $DIR/const-param-before-other-params.rs:4:21 - | -LL | fn foo(_: &T) { - | --------------^- help: reorder the parameters: lifetimes, then types, then consts: `` - error: lifetime parameters must be declared prior to const parameters - --> $DIR/const-param-before-other-params.rs:8:21 + --> $DIR/const-param-before-other-params.rs:4:21 | LL | fn bar(_: &'a ()) { | --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>` +error: type parameters must be declared prior to const parameters + --> $DIR/const-param-before-other-params.rs:8:21 + | +LL | fn foo(_: &T) { + | --------------^- help: reorder the parameters: lifetimes, then types, then consts: `` + error: aborting due to 2 previous errors