]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Prevent passing generic arguments to impl traits in argument position
authorPhilip Herron <herron.philip@googlemail.com>
Wed, 7 May 2025 15:07:43 +0000 (16:07 +0100)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 5 Aug 2025 14:36:41 +0000 (16:36 +0200)
When using impl traits in argument position (APIT), they are desugared into generics,
and supplying explicit generic arguments is not allowed. This commit adds the error
diagnostic E0632 for attempting to pass generic arguments to impl traits, completing
the implementation of the APIT feature.

gcc/rust/ChangeLog:

* ast/rust-desugar-apit.cc: track if this is a impl-trait generic
* ast/rust-item.h (class TypeParam): add field to track if from impl trait
* hir/rust-ast-lower-type.cc (ASTLowerGenericParam::visit): likewise
* hir/tree/rust-hir-item.cc (TypeParam::TypeParam): upate hir as well
(TypeParam::operator=): likewise
* hir/tree/rust-hir-item.h (class TypeParam): likewise
* typecheck/rust-tyty-subst.cc (SubstitutionParamMapping::get_generic_param): add error
* typecheck/rust-tyty-subst.h: add const getter for the associated TypeParm

gcc/testsuite/ChangeLog:

* rust/compile/nr2/exclude: nr2 cant handle this
* rust/compile/impl_trait_generic_arg.rs: New test.

Signed-off-by: Philip Herron <herron.philip@googlemail.com>
gcc/rust/ast/rust-desugar-apit.cc
gcc/rust/ast/rust-item.h
gcc/rust/hir/rust-ast-lower-type.cc
gcc/rust/hir/tree/rust-hir-item.cc
gcc/rust/hir/tree/rust-hir-item.h
gcc/rust/typecheck/rust-tyty-subst.cc
gcc/rust/typecheck/rust-tyty-subst.h
gcc/testsuite/rust/compile/impl_trait_generic_arg.rs [new file with mode: 0644]
gcc/testsuite/rust/compile/nr2/exclude

index 2f31bcfe7a327c499c90c34eeb27ac2a915aa90e..5b9486ea6714c11228581bab78b644742b3e491b 100644 (file)
@@ -203,7 +203,8 @@ public:
 
     // Create the new generic parameter
     auto generic_param = std::unique_ptr<TypeParam> (
-      new TypeParam (ident, type.get_locus (), std::move (bounds)));
+      new TypeParam (ident, type.get_locus (), std::move (bounds), nullptr, {},
+                    true /*from impl trait*/));
 
     // Store the generic parameter to be added to the function signature
     implicit_generic_params.push_back (std::move (generic_param));
@@ -241,7 +242,8 @@ public:
 
     // Create the new generic parameter
     auto generic_param = std::unique_ptr<TypeParam> (
-      new TypeParam (ident, type.get_locus (), std::move (bounds)));
+      new TypeParam (ident, type.get_locus (), std::move (bounds), nullptr, {},
+                    true /*from impl trait*/));
 
     // Store the generic parameter to be added to the function signature
     implicit_generic_params.push_back (std::move (generic_param));
index 062f85d221276688773a39cf5ead308f83358d58..247a65f39c2ec106976abac2ae91f9120b996c38 100644 (file)
@@ -51,21 +51,12 @@ class TypePath;
 // A type generic parameter (as opposed to a lifetime generic parameter)
 class TypeParam : public GenericParam
 {
-  // bool has_outer_attribute;
-  // std::unique_ptr<Attribute> outer_attr;
   AST::AttrVec outer_attrs;
-
   Identifier type_representation;
-
-  // bool has_type_param_bounds;
-  // TypeParamBounds type_param_bounds;
-  std::vector<std::unique_ptr<TypeParamBound>>
-    type_param_bounds; // inlined form
-
-  // bool has_type;
+  std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds;
   std::unique_ptr<Type> type;
-
   location_t locus;
+  bool was_impl_trait;
 
 public:
   Identifier get_type_representation () const { return type_representation; }
@@ -85,18 +76,19 @@ public:
             std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds
             = std::vector<std::unique_ptr<TypeParamBound>> (),
             std::unique_ptr<Type> type = nullptr,
-            AST::AttrVec outer_attrs = {})
+            AST::AttrVec outer_attrs = {}, bool was_impl_trait = false)
     : GenericParam (Analysis::Mappings::get ().get_next_node_id ()),
       outer_attrs (std::move (outer_attrs)),
       type_representation (std::move (type_representation)),
       type_param_bounds (std::move (type_param_bounds)),
-      type (std::move (type)), locus (locus)
+      type (std::move (type)), locus (locus), was_impl_trait (was_impl_trait)
   {}
 
   // Copy constructor uses clone
   TypeParam (TypeParam const &other)
     : GenericParam (other.node_id), outer_attrs (other.outer_attrs),
-      type_representation (other.type_representation), locus (other.locus)
+      type_representation (other.type_representation), locus (other.locus),
+      was_impl_trait (other.was_impl_trait)
   {
     // guard to prevent null pointer dereference
     if (other.type != nullptr)
@@ -114,6 +106,7 @@ public:
     outer_attrs = other.outer_attrs;
     locus = other.locus;
     node_id = other.node_id;
+    was_impl_trait = other.was_impl_trait;
 
     // guard to prevent null pointer dereference
     if (other.type != nullptr)
@@ -153,17 +146,19 @@ public:
     return type;
   }
 
-  // TODO: mutable getter seems kinda dodgy
   std::vector<std::unique_ptr<TypeParamBound>> &get_type_param_bounds ()
   {
     return type_param_bounds;
   }
+
   const std::vector<std::unique_ptr<TypeParamBound>> &
   get_type_param_bounds () const
   {
     return type_param_bounds;
   }
 
+  bool from_impl_trait () const { return was_impl_trait; }
+
 protected:
   // Clone function implementation as virtual method
   TypeParam *clone_generic_param_impl () const override
index 4e44b1b9ce37ea39b47753ad11b1cbe7ff893df9..1841576b29f4b0a8091e8134638063ab5a850eea 100644 (file)
@@ -620,7 +620,8 @@ ASTLowerGenericParam::visit (AST::TypeParam &param)
   translated
     = new HIR::TypeParam (mapping, param.get_type_representation (),
                          param.get_locus (), std::move (type_param_bounds),
-                         std::move (type), param.get_outer_attrs ());
+                         std::move (type), param.get_outer_attrs (),
+                         param.from_impl_trait ());
 }
 
 HIR::TypeParamBound *
index 160f710408af430e9926935bcf5ba934ea38391e..1406e7aeb51566d724aaff981c48a7ec123fdef8 100644 (file)
@@ -26,16 +26,18 @@ TypeParam::TypeParam (
   Analysis::NodeMapping mappings, Identifier type_representation,
   location_t locus,
   std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds,
-  tl::optional<std::unique_ptr<Type>> type, AST::AttrVec outer_attrs)
+  tl::optional<std::unique_ptr<Type>> type, AST::AttrVec outer_attrs,
+  bool was_impl_trait)
   : GenericParam (mappings), outer_attrs (std::move (outer_attrs)),
     type_representation (std::move (type_representation)),
     type_param_bounds (std::move (type_param_bounds)), type (std::move (type)),
-    locus (locus)
+    locus (locus), was_impl_trait (was_impl_trait)
 {}
 
 TypeParam::TypeParam (TypeParam const &other)
   : GenericParam (other.mappings), outer_attrs (other.outer_attrs),
-    type_representation (other.type_representation), locus (other.locus)
+    type_representation (other.type_representation), locus (other.locus),
+    was_impl_trait (other.was_impl_trait)
 {
   // guard to prevent null pointer dereference
   if (other.has_type ())
@@ -55,6 +57,7 @@ TypeParam::operator= (TypeParam const &other)
   outer_attrs = other.outer_attrs;
   locus = other.locus;
   mappings = other.mappings;
+  was_impl_trait = other.was_impl_trait;
 
   // guard to prevent null pointer dereference
   if (other.has_type ())
index 37f599cdee4a4f1cc6c62f9f9018a7ce11a5cb98..d61027732ab91791fbd273c65fd983da573c5400 100644 (file)
@@ -95,17 +95,11 @@ protected:
 class TypeParam : public GenericParam
 {
   AST::AttrVec outer_attrs;
-
   Identifier type_representation;
-
-  // bool has_type_param_bounds;
-  // TypeParamBounds type_param_bounds;
-  std::vector<std::unique_ptr<TypeParamBound>>
-    type_param_bounds; // inlined form
-
+  std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds;
   tl::optional<std::unique_ptr<Type>> type;
-
   location_t locus;
+  bool was_impl_trait;
 
 public:
   // Returns whether the type of the type param has been specified.
@@ -121,9 +115,9 @@ public:
   TypeParam (Analysis::NodeMapping mappings, Identifier type_representation,
             location_t locus = UNDEF_LOCATION,
             std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds
-            = std::vector<std::unique_ptr<TypeParamBound>> (),
+            = {},
             tl::optional<std::unique_ptr<Type>> type = tl::nullopt,
-            AST::AttrVec outer_attrs = std::vector<AST::Attribute> ());
+            AST::AttrVec outer_attrs = {}, bool was_impl_trait = false);
 
   // Copy constructor uses clone
   TypeParam (TypeParam const &other);
@@ -154,6 +148,8 @@ public:
 
   std::vector<std::unique_ptr<TypeParamBound>> &get_type_param_bounds ();
 
+  bool from_impl_trait () const { return was_impl_trait; }
+
 protected:
   // Clone function implementation as (not pure) virtual method
   TypeParam *clone_generic_param_impl () const override
index bdb6474aeeb466ac6a163958c9fa6deab59e47be..28d311a8aad20ea1eb4438f95192366724f43057 100644 (file)
@@ -72,6 +72,12 @@ SubstitutionParamMapping::get_generic_param ()
   return generic;
 }
 
+const HIR::TypeParam &
+SubstitutionParamMapping::get_generic_param () const
+{
+  return generic;
+}
+
 bool
 SubstitutionParamMapping::needs_substitution () const
 {
@@ -618,7 +624,6 @@ SubstitutionRef::get_mappings_from_generic_args (
          if (args.get_binding_args ().size () > get_num_associated_bindings ())
            {
              rich_location r (line_table, args.get_locus ());
-
              rust_error_at (r,
                             "generic item takes at most %lu type binding "
                             "arguments but %lu were supplied",
@@ -702,7 +707,19 @@ SubstitutionRef::get_mappings_from_generic_args (
          return SubstitutionArgumentMappings::error ();
        }
 
-      SubstitutionArg subst_arg (&substitutions.at (offs), resolved);
+      const auto &param_mapping = substitutions.at (offs);
+      const auto &type_param = param_mapping.get_generic_param ();
+      if (type_param.from_impl_trait ())
+       {
+         rich_location r (line_table, arg->get_locus ());
+         r.add_fixit_remove (arg->get_locus ());
+         rust_error_at (r, ErrorCode::E0632,
+                        "cannot provide explicit generic arguments when "
+                        "%<impl Trait%> is used in argument position");
+         return SubstitutionArgumentMappings::error ();
+       }
+
+      SubstitutionArg subst_arg (&param_mapping, resolved);
       offs++;
       mappings.push_back (std::move (subst_arg));
     }
index e6ed1fc42d670adcad2dee6608d473771f790c44..2f5de23aa00fa16e1014243f0a3a22f980a2ab9c 100644 (file)
@@ -60,6 +60,7 @@ public:
   const ParamType *get_param_ty () const;
 
   HIR::TypeParam &get_generic_param ();
+  const HIR::TypeParam &get_generic_param () const;
 
   // this is used for the backend to override the HirId ref of the param to
   // what the concrete type is for the rest of the context
diff --git a/gcc/testsuite/rust/compile/impl_trait_generic_arg.rs b/gcc/testsuite/rust/compile/impl_trait_generic_arg.rs
new file mode 100644 (file)
index 0000000..ecdb088
--- /dev/null
@@ -0,0 +1,24 @@
+#[lang = "sized"]
+trait Sized {}
+
+trait Foo {
+    fn id(&self) -> u8;
+}
+
+struct Bar;
+
+impl Foo for Bar {
+    fn id(&self) -> u8 {
+        1
+    }
+}
+
+fn takes(val: impl Foo) -> u8 {
+    val.id()
+}
+
+fn main() {
+    let b = Bar;
+    let x = takes::<Bar>(b);
+    // { dg-error "cannot provide explicit generic arguments when .impl Trait. is used in argument position .E0632." "" { target *-*-* } .-1 }
+}
index d3bdb1cce0dfe5f0af74c7d823c7a7a5ae20a48b..b9b9e39aa82c4c9bba7c44c6ff261603c3c022eb 100644 (file)
@@ -17,4 +17,5 @@ issue-3649.rs
 issue-1487.rs
 issue-2015.rs
 issue-3454.rs
+impl_trait_generic_arg.rs
 # please don't delete the trailing newline