about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2020-03-21 13:06:40 +0100
committerGitHub <noreply@github.com>2020-03-21 13:06:40 +0100
commit266801d80683ea2ea023d370ff1edd857c66fe15 (patch)
treef94bc5cd8db06d92e75c81caf5528769ff1f002c
parent276b54e9c930c4ff015e1958ad1c640deffd29b2 (diff)
parent17c94c6746e94a4349a05bbf6326bebe35893acc (diff)
downloadrust-266801d80683ea2ea023d370ff1edd857c66fe15.tar.gz
rust-266801d80683ea2ea023d370ff1edd857c66fe15.zip
Rollup merge of #70032 - lcnr:issue69970, r=varkor
put type params in front of const params in generics_of

fixes #69970

r? @varkor
-rw-r--r--src/librustc_ast_passes/ast_validation.rs2
-rw-r--r--src/librustc_typeck/collect.rs94
-rw-r--r--src/test/ui/const-generics/argument_order.rs9
-rw-r--r--src/test/ui/const-generics/argument_order.stderr16
4 files changed, 84 insertions, 37 deletions
diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs
index 541c681840f..b4363778094 100644
--- a/src/librustc_ast_passes/ast_validation.rs
+++ b/src/librustc_ast_passes/ast_validation.rs
@@ -645,6 +645,8 @@ impl<'a> AstValidator<'a> {
     }
 }
 
+/// Checks that generic parameters are in the correct order,
+/// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
 fn validate_generic_param_order<'a>(
     sess: &Session,
     handler: &rustc_errors::Handler,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 9fbff039942..a79c0653077 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1306,47 +1306,67 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
     // Now create the real type and const parameters.
     let type_start = own_start - has_self as u32 + params.len() as u32;
     let mut i = 0;
-    params.extend(ast_generics.params.iter().filter_map(|param| {
-        let kind = match param.kind {
-            GenericParamKind::Type { ref default, synthetic, .. } => {
-                if !allow_defaults && default.is_some() {
-                    if !tcx.features().default_type_parameter_fallback {
-                        tcx.struct_span_lint_hir(
-                            lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
-                            param.hir_id,
-                            param.span,
-                            |lint| {
-                                lint.build(
-                                    "defaults for type parameters are only allowed in \
-                                            `struct`, `enum`, `type`, or `trait` definitions.",
-                                )
-                                .emit();
-                            },
-                        );
-                    }
-                }
 
-                ty::GenericParamDefKind::Type {
-                    has_default: default.is_some(),
-                    object_lifetime_default: object_lifetime_defaults
-                        .as_ref()
-                        .map_or(rl::Set1::Empty, |o| o[i]),
-                    synthetic,
+    // FIXME(const_generics): a few places in the compiler expect generic params
+    // to be in the order lifetimes, then type params, then const params.
+    //
+    // To prevent internal errors in case const parameters are supplied before
+    // type parameters we first add all type params, then all const params.
+    params.extend(ast_generics.params.iter().filter_map(|param| {
+        if let GenericParamKind::Type { ref default, synthetic, .. } = param.kind {
+            if !allow_defaults && default.is_some() {
+                if !tcx.features().default_type_parameter_fallback {
+                    tcx.struct_span_lint_hir(
+                        lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
+                        param.hir_id,
+                        param.span,
+                        |lint| {
+                            lint.build(
+                                "defaults for type parameters are only allowed in \
+                                        `struct`, `enum`, `type`, or `trait` definitions.",
+                            )
+                            .emit();
+                        },
+                    );
                 }
             }
-            GenericParamKind::Const { .. } => ty::GenericParamDefKind::Const,
-            _ => return None,
-        };
 
-        let param_def = ty::GenericParamDef {
-            index: type_start + i as u32,
-            name: param.name.ident().name,
-            def_id: tcx.hir().local_def_id(param.hir_id),
-            pure_wrt_drop: param.pure_wrt_drop,
-            kind,
-        };
-        i += 1;
-        Some(param_def)
+            let kind = ty::GenericParamDefKind::Type {
+                has_default: default.is_some(),
+                object_lifetime_default: object_lifetime_defaults
+                    .as_ref()
+                    .map_or(rl::Set1::Empty, |o| o[i]),
+                synthetic,
+            };
+
+            let param_def = ty::GenericParamDef {
+                index: type_start + i as u32,
+                name: param.name.ident().name,
+                def_id: tcx.hir().local_def_id(param.hir_id),
+                pure_wrt_drop: param.pure_wrt_drop,
+                kind,
+            };
+            i += 1;
+            Some(param_def)
+        } else {
+            None
+        }
+    }));
+
+    params.extend(ast_generics.params.iter().filter_map(|param| {
+        if let GenericParamKind::Const { .. } = param.kind {
+            let param_def = ty::GenericParamDef {
+                index: type_start + i as u32,
+                name: param.name.ident().name,
+                def_id: tcx.hir().local_def_id(param.hir_id),
+                pure_wrt_drop: param.pure_wrt_drop,
+                kind: ty::GenericParamDefKind::Const,
+            };
+            i += 1;
+            Some(param_def)
+        } else {
+            None
+        }
     }));
 
     // provide junk type parameter defs - the only place that
diff --git a/src/test/ui/const-generics/argument_order.rs b/src/test/ui/const-generics/argument_order.rs
new file mode 100644
index 00000000000..3446600d049
--- /dev/null
+++ b/src/test/ui/const-generics/argument_order.rs
@@ -0,0 +1,9 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+struct Bad<const N: usize, T> { //~ ERROR type parameters must be declared prior
+    arr: [u8; { N }],
+    another: T,
+}
+
+fn main() { }
diff --git a/src/test/ui/const-generics/argument_order.stderr b/src/test/ui/const-generics/argument_order.stderr
new file mode 100644
index 00000000000..1e3b364eb60
--- /dev/null
+++ b/src/test/ui/const-generics/argument_order.stderr
@@ -0,0 +1,16 @@
+error: type parameters must be declared prior to const parameters
+  --> $DIR/argument_order.rs:4:28
+   |
+LL | struct Bad<const N: usize, T> {
+   |           -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
+
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/argument_order.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: aborting due to previous error
+