https://gcc.gnu.org/g:fc6b54365731c2ebfa1974058c48772e03203fdd

commit fc6b54365731c2ebfa1974058c48772e03203fdd
Author: Philip Herron <herron.phi...@googlemail.com>
Date:   Wed May 7 16:07:43 2025 +0100

    gccrs: Prevent passing generic arguments to impl traits in argument position
    
    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.phi...@googlemail.com>

Diff:
---
 gcc/rust/ast/rust-desugar-apit.cc                  |  6 ++++--
 gcc/rust/ast/rust-item.h                           | 25 +++++++++-------------
 gcc/rust/hir/rust-ast-lower-type.cc                |  3 ++-
 gcc/rust/hir/tree/rust-hir-item.cc                 |  9 +++++---
 gcc/rust/hir/tree/rust-hir-item.h                  | 16 ++++++--------
 gcc/rust/typecheck/rust-tyty-subst.cc              | 21 ++++++++++++++++--
 gcc/rust/typecheck/rust-tyty-subst.h               |  1 +
 .../rust/compile/impl_trait_generic_arg.rs         | 24 +++++++++++++++++++++
 gcc/testsuite/rust/compile/nr2/exclude             |  1 +
 9 files changed, 73 insertions(+), 33 deletions(-)

diff --git a/gcc/rust/ast/rust-desugar-apit.cc 
b/gcc/rust/ast/rust-desugar-apit.cc
index 2f31bcfe7a32..5b9486ea6714 100644
--- a/gcc/rust/ast/rust-desugar-apit.cc
+++ b/gcc/rust/ast/rust-desugar-apit.cc
@@ -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));
diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h
index f507c90dc962..2f53f8d117e4 100644
--- a/gcc/rust/ast/rust-item.h
+++ b/gcc/rust/ast/rust-item.h
@@ -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
diff --git a/gcc/rust/hir/rust-ast-lower-type.cc 
b/gcc/rust/hir/rust-ast-lower-type.cc
index 6a5b7dba866c..b83d8043800e 100644
--- a/gcc/rust/hir/rust-ast-lower-type.cc
+++ b/gcc/rust/hir/rust-ast-lower-type.cc
@@ -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 *
diff --git a/gcc/rust/hir/tree/rust-hir-item.cc 
b/gcc/rust/hir/tree/rust-hir-item.cc
index 160f710408af..1406e7aeb515 100644
--- a/gcc/rust/hir/tree/rust-hir-item.cc
+++ b/gcc/rust/hir/tree/rust-hir-item.cc
@@ -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 ())
diff --git a/gcc/rust/hir/tree/rust-hir-item.h 
b/gcc/rust/hir/tree/rust-hir-item.h
index 41ba38c4f6d7..dc8f9f9dd7a8 100644
--- a/gcc/rust/hir/tree/rust-hir-item.h
+++ b/gcc/rust/hir/tree/rust-hir-item.h
@@ -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
diff --git a/gcc/rust/typecheck/rust-tyty-subst.cc 
b/gcc/rust/typecheck/rust-tyty-subst.cc
index c3033eed5f7d..8279c8feacd4 100644
--- a/gcc/rust/typecheck/rust-tyty-subst.cc
+++ b/gcc/rust/typecheck/rust-tyty-subst.cc
@@ -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));
     }
diff --git a/gcc/rust/typecheck/rust-tyty-subst.h 
b/gcc/rust/typecheck/rust-tyty-subst.h
index 8a43b917a54f..084b453c7c51 100644
--- a/gcc/rust/typecheck/rust-tyty-subst.h
+++ b/gcc/rust/typecheck/rust-tyty-subst.h
@@ -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
index 000000000000..ecdb08803b40
--- /dev/null
+++ b/gcc/testsuite/rust/compile/impl_trait_generic_arg.rs
@@ -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 }
+}
diff --git a/gcc/testsuite/rust/compile/nr2/exclude 
b/gcc/testsuite/rust/compile/nr2/exclude
index d3bdb1cce0df..b9b9e39aa82c 100644
--- a/gcc/testsuite/rust/compile/nr2/exclude
+++ b/gcc/testsuite/rust/compile/nr2/exclude
@@ -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

Reply via email to