From 6311097e75c7640ff684747255f443cfe8e1dcb9 Mon Sep 17 00:00:00 2001 From: Lucas Ly Ba Date: Wed, 15 Oct 2025 13:23:05 +0000 Subject: [PATCH 01/14] gccrs: fix segfault on exported macro An imbricated exported macro leads to a segfault. gcc/rust/ChangeLog: * metadata/rust-export-metadata.cc (ExportContext::emit_macro): Change method argument NodeId to AST::MacroRulesDefinition. * metadata/rust-export-metadata.h: Likewise. * util/rust-hir-map.cc (Mappings::insert_exported_macro): Insert AST::MacroRulesDefinition instead of NodeId. * util/rust-hir-map.h: Change methods declarations of exported macros. gcc/testsuite/ChangeLog: * rust/compile/issue-3617.rs: New test. Signed-off-by: Lucas Ly Ba --- gcc/rust/metadata/rust-export-metadata.cc | 9 ++++----- gcc/rust/metadata/rust-export-metadata.h | 2 +- gcc/rust/util/rust-hir-map.cc | 4 ++-- gcc/rust/util/rust-hir-map.h | 4 ++-- gcc/testsuite/rust/compile/issue-3617.rs | 14 ++++++++++++++ 5 files changed, 23 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/rust/compile/issue-3617.rs diff --git a/gcc/rust/metadata/rust-export-metadata.cc b/gcc/rust/metadata/rust-export-metadata.cc index 4dfc28036c35..a8d4af129db3 100644 --- a/gcc/rust/metadata/rust-export-metadata.cc +++ b/gcc/rust/metadata/rust-export-metadata.cc @@ -23,6 +23,7 @@ #include "rust-ast-dump.h" #include "rust-abi.h" #include "rust-item.h" +#include "rust-macro.h" #include "rust-object-export.h" #include "md5.h" @@ -111,14 +112,12 @@ ExportContext::emit_function (const HIR::Function &fn) } void -ExportContext::emit_macro (NodeId macro) +ExportContext::emit_macro (AST::MacroRulesDefinition ¯o) { std::stringstream oss; AST::Dump dumper (oss); - AST::Item *item = mappings.lookup_ast_item (macro).value (); - - dumper.go (*item); + dumper.go (macro); public_interface_buffer += oss.str (); } @@ -195,7 +194,7 @@ PublicInterface::gather_export_data () vis_item.accept_vis (visitor); } - for (const auto ¯o : mappings.get_exported_macros ()) + for (auto ¯o : mappings.get_exported_macros ()) context.emit_macro (macro); } diff --git a/gcc/rust/metadata/rust-export-metadata.h b/gcc/rust/metadata/rust-export-metadata.h index ee006cd83d1a..7747d95bc153 100644 --- a/gcc/rust/metadata/rust-export-metadata.h +++ b/gcc/rust/metadata/rust-export-metadata.h @@ -48,7 +48,7 @@ class ExportContext * directly refer to them using their NodeId. There's no need to keep an HIR * node for them. */ - void emit_macro (NodeId macro); + void emit_macro (AST::MacroRulesDefinition ¯o); const std::string &get_interface_buffer () const; diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc index 4629e6a57026..1587c7ee7a22 100644 --- a/gcc/rust/util/rust-hir-map.cc +++ b/gcc/rust/util/rust-hir-map.cc @@ -925,10 +925,10 @@ Mappings::lookup_macro_invocation (AST::MacroInvocation &invoc) void Mappings::insert_exported_macro (AST::MacroRulesDefinition &def) { - exportedMacros.emplace_back (def.get_node_id ()); + exportedMacros.emplace_back (def); } -std::vector & +std::vector Mappings::get_exported_macros () { return exportedMacros; diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h index c8fafa4a35f0..8a284cb938bd 100644 --- a/gcc/rust/util/rust-hir-map.h +++ b/gcc/rust/util/rust-hir-map.h @@ -279,7 +279,7 @@ class Mappings lookup_macro_invocation (AST::MacroInvocation &invoc); void insert_exported_macro (AST::MacroRulesDefinition &def); - std::vector &get_exported_macros (); + std::vector get_exported_macros (); void insert_derive_proc_macros (CrateNum num, std::vector macros); @@ -408,7 +408,7 @@ class Mappings std::map> macroMappings; std::map macroInvocations; - std::vector exportedMacros; + std::vector exportedMacros; // Procedural macros std::map> diff --git a/gcc/testsuite/rust/compile/issue-3617.rs b/gcc/testsuite/rust/compile/issue-3617.rs new file mode 100644 index 000000000000..64c2166c112d --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3617.rs @@ -0,0 +1,14 @@ +macro_rules! quote_tokens { + () => { + #[macro_export] + macro_rules! inner { + () => { + $crate:: + } + } + }; +} + +pub fn main() { + quote_tokens!(); +} From 9a93563a50b67e02a6d4911c09f4edb8018ed6e9 Mon Sep 17 00:00:00 2001 From: Yap Zhi Heng Date: Sun, 26 Oct 2025 10:49:28 +0800 Subject: [PATCH 02/14] gccrs: Add minus sign compilation for LiteralPattern GIMPLE output for literalpattern_neg.rs test case: ... x = -55; RUSTTMP.2 = x; if (RUSTTMP.2 == 55) goto ; else goto ; : { RUSTTMP.1 = 1; goto ; } : if (RUSTTMP.2 == -55) goto ; else goto ; : { RUSTTMP.1 = 0; goto ; } : if (1 != 0) goto ; else goto ; : { RUSTTMP.1 = 1; goto ; } ... gcc/rust/ChangeLog: * parse/rust-parse-impl.h (parse_literal_or_range_pattern): Parse minus sign properly for LiteralPattern. * ast/rust-pattern.h (LiteralPattern): Add has_minus boolean for LiteralPattern. * hir/tree/rust-hir-pattern.h (LiteralPattern): Ditto. * ast/rust-pattern.cc (LiteralPattern::as_string): Update to include minus sign if present. * hir/tree/rust-hir.cc (LiteralPattern::as_string): Ditto. * hir/rust-ast-lower-pattern.cc (visit(LiteralPattern)): Pass has_minus boolean from AST to HIR. * backend/rust-compile-pattern.cc (CompilePatternCheckExpr::visit(LiteralPattern)): Compile litexpr as negative if minus sign is present. Signed-off-by: Yap Zhi Heng --- gcc/rust/ast/rust-pattern.cc | 2 +- gcc/rust/ast/rust-pattern.h | 22 +++++++++++++++++-- gcc/rust/backend/rust-compile-pattern.cc | 2 ++ gcc/rust/hir/rust-ast-lower-pattern.cc | 3 ++- gcc/rust/hir/tree/rust-hir-pattern.h | 14 ++++++++++-- gcc/rust/hir/tree/rust-hir.cc | 2 +- gcc/rust/parse/rust-parse-impl.h | 2 +- .../execute/torture/literalpattern_neg.rs | 9 ++++++++ 8 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/rust/execute/torture/literalpattern_neg.rs diff --git a/gcc/rust/ast/rust-pattern.cc b/gcc/rust/ast/rust-pattern.cc index a2fe5d590813..80189d3746bf 100644 --- a/gcc/rust/ast/rust-pattern.cc +++ b/gcc/rust/ast/rust-pattern.cc @@ -48,7 +48,7 @@ tokenid_to_rangekind (TokenId id) std::string LiteralPattern::as_string () const { - return lit.as_string (); + return (has_minus ? "-" : "") + lit.as_string (); } std::string diff --git a/gcc/rust/ast/rust-pattern.h b/gcc/rust/ast/rust-pattern.h index 0da1981928f9..3b1bd1c29ecf 100644 --- a/gcc/rust/ast/rust-pattern.h +++ b/gcc/rust/ast/rust-pattern.h @@ -30,6 +30,7 @@ class LiteralPattern : public Pattern Literal lit; location_t locus; NodeId node_id; + bool has_minus; public: std::string as_string () const override; @@ -37,17 +38,34 @@ class LiteralPattern : public Pattern // Constructor for a literal pattern LiteralPattern (Literal lit, location_t locus) : lit (std::move (lit)), locus (locus), - node_id (Analysis::Mappings::get ().get_next_node_id ()) + node_id (Analysis::Mappings::get ().get_next_node_id ()), + has_minus (false) + {} + + LiteralPattern (Literal lit, location_t locus, bool has_minus) + : lit (std::move (lit)), locus (locus), + node_id (Analysis::Mappings::get ().get_next_node_id ()), + has_minus (has_minus) {} LiteralPattern (std::string val, Literal::LitType type, location_t locus, PrimitiveCoreType type_hint) : lit (Literal (std::move (val), type, type_hint)), locus (locus), - node_id (Analysis::Mappings::get ().get_next_node_id ()) + node_id (Analysis::Mappings::get ().get_next_node_id ()), + has_minus (false) + {} + + LiteralPattern (std::string val, Literal::LitType type, location_t locus, + PrimitiveCoreType type_hint, bool has_minus) + : lit (Literal (std::move (val), type, type_hint)), locus (locus), + node_id (Analysis::Mappings::get ().get_next_node_id ()), + has_minus (has_minus) {} location_t get_locus () const override final { return locus; } + bool get_has_minus () const { return has_minus; } + void accept_vis (ASTVisitor &vis) override; NodeId get_node_id () const override { return node_id; } diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index 82333dc39c04..3a983e9bc887 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -87,6 +87,8 @@ CompilePatternCheckExpr::visit (HIR::LiteralPattern &pattern) auto litexpr = std::make_unique ( HIR::LiteralExpr (pattern.get_mappings (), pattern.get_literal (), pattern.get_locus (), std::vector ())); + if (pattern.get_has_minus ()) + litexpr->set_negative (); // Note: Floating point literals are currently accepted but will likely be // forbidden in LiteralPatterns in a future version of Rust. diff --git a/gcc/rust/hir/rust-ast-lower-pattern.cc b/gcc/rust/hir/rust-ast-lower-pattern.cc index 4250adbfbab6..c941a5c9af94 100644 --- a/gcc/rust/hir/rust-ast-lower-pattern.cc +++ b/gcc/rust/hir/rust-ast-lower-pattern.cc @@ -280,7 +280,8 @@ ASTLoweringPattern::visit (AST::LiteralPattern &pattern) HIR::Literal l = lower_literal (pattern.get_literal ()); translated - = new HIR::LiteralPattern (mapping, std::move (l), pattern.get_locus ()); + = new HIR::LiteralPattern (mapping, std::move (l), pattern.get_locus (), + pattern.get_has_minus ()); } void diff --git a/gcc/rust/hir/tree/rust-hir-pattern.h b/gcc/rust/hir/tree/rust-hir-pattern.h index 89b9cc6a06ce..a2c408fdc772 100644 --- a/gcc/rust/hir/tree/rust-hir-pattern.h +++ b/gcc/rust/hir/tree/rust-hir-pattern.h @@ -32,19 +32,27 @@ class LiteralPattern : public Pattern Literal lit; location_t locus; Analysis::NodeMapping mappings; + bool has_minus; public: std::string as_string () const override; // Constructor for a literal pattern LiteralPattern (Analysis::NodeMapping mappings, Literal lit, location_t locus) - : lit (std::move (lit)), locus (locus), mappings (mappings) + : lit (std::move (lit)), locus (locus), mappings (mappings), + has_minus (false) + {} + + LiteralPattern (Analysis::NodeMapping mappings, Literal lit, location_t locus, + bool has_minus) + : lit (std::move (lit)), locus (locus), mappings (mappings), + has_minus (has_minus) {} LiteralPattern (Analysis::NodeMapping mappings, std::string val, Literal::LitType type, location_t locus) : lit (Literal (std::move (val), type, PrimitiveCoreType::CORETYPE_STR)), - locus (locus), mappings (mappings) + locus (locus), mappings (mappings), has_minus (false) {} location_t get_locus () const override { return locus; } @@ -65,6 +73,8 @@ class LiteralPattern : public Pattern Literal &get_literal () { return lit; } const Literal &get_literal () const { return lit; } + bool get_has_minus () const { return has_minus; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc index ce10b02303c3..57f560b06d3e 100644 --- a/gcc/rust/hir/tree/rust-hir.cc +++ b/gcc/rust/hir/tree/rust-hir.cc @@ -2634,7 +2634,7 @@ StructPattern::as_string () const std::string LiteralPattern::as_string () const { - return lit.as_string (); + return (has_minus ? "-" : "") + lit.as_string (); } std::string diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index ec4c1c1d6c7c..e79727704553 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -10345,7 +10345,7 @@ Parser::parse_literal_or_range_pattern () return std::unique_ptr ( new AST::LiteralPattern (range_lower->get_str (), type, range_lower->get_locus (), - range_lower->get_type_hint ())); + range_lower->get_type_hint (), has_minus)); } } diff --git a/gcc/testsuite/rust/execute/torture/literalpattern_neg.rs b/gcc/testsuite/rust/execute/torture/literalpattern_neg.rs new file mode 100644 index 000000000000..3553c4a3462a --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/literalpattern_neg.rs @@ -0,0 +1,9 @@ +fn main() -> i32 { + let x = -55; + + match x { + 55 => 1, + -55 => 0, // correct case + _ => 1 + } +} \ No newline at end of file From 8d7edfab7d6fef503ff8904ed92c0d44192506f9 Mon Sep 17 00:00:00 2001 From: vishruth-thimmaiah Date: Wed, 29 Oct 2025 22:50:49 +0530 Subject: [PATCH 03/14] gccrs: Fix ICE with non-trailing const defaults When a const generic with a default value is not trailing, emit an error. gcc/rust/ChangeLog: * parse/rust-parse-impl.h (Parser::parse_generic_params): Emit an error when const generics with a default value is not trailing. gcc/testsuite/ChangeLog: * rust/compile/const_generics_17.rs: New test. * rust/compile/generics14.rs: New test. Signed-off-by: vishruth-thimmaiah --- gcc/rust/parse/rust-parse-impl.h | 34 +++++++++++++++++-- .../rust/compile/const_generics_17.rs | 3 ++ gcc/testsuite/rust/compile/generics14.rs | 1 + 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/rust/compile/const_generics_17.rs create mode 100644 gcc/testsuite/rust/compile/generics14.rs diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index e79727704553..62831ebbf10e 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -3262,8 +3262,12 @@ Parser::parse_generic_params (EndTokenPred is_end_token) // Did we parse a generic type param yet auto type_seen = false; + // Did we parse a const param with a default value yet + auto const_with_default_seen = false; // Did the user write a lifetime parameter after a type one auto order_error = false; + // Did the user write a const param with a default value after a type one + auto const_with_default_order_error = false; // parse lifetime params while (!is_end_token (lexer.peek_token ()->get_id ())) @@ -3271,12 +3275,29 @@ Parser::parse_generic_params (EndTokenPred is_end_token) auto param = parse_generic_param (is_end_token); if (param) { - // TODO: Handle `Const` here as well if necessary if (param->get_kind () == AST::GenericParam::Kind::Type) - type_seen = true; + { + type_seen = true; + if (const_with_default_seen) + const_with_default_order_error = true; + } else if (param->get_kind () == AST::GenericParam::Kind::Lifetime && type_seen) - order_error = true; + { + order_error = true; + if (const_with_default_seen) + const_with_default_order_error = true; + } + else if (param->get_kind () == AST::GenericParam::Kind::Const) + { + type_seen = true; + AST::ConstGenericParam *const_param + = static_cast (param.get ()); + if (const_param->has_default_value ()) + const_with_default_seen = true; + else if (const_with_default_seen) + const_with_default_order_error = true; + } generic_params.emplace_back (std::move (param)); maybe_skip_token (COMMA); @@ -3293,6 +3314,13 @@ Parser::parse_generic_params (EndTokenPred is_end_token) "must be declared prior to type and const parameters"); add_error (std::move (error)); } + if (const_with_default_order_error) + { + Error error (generic_params.front ()->get_locus (), + "invalid order for generic parameters: generic parameters " + "with a default must be trailing"); + add_error (std::move (error)); + } generic_params.shrink_to_fit (); return generic_params; diff --git a/gcc/testsuite/rust/compile/const_generics_17.rs b/gcc/testsuite/rust/compile/const_generics_17.rs new file mode 100644 index 000000000000..f65ca22b326f --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_17.rs @@ -0,0 +1,3 @@ +struct Foo; // { dg-error "invalid order for generic parameters: generic parameters with a default must be trailing" } + +impl Foo {} diff --git a/gcc/testsuite/rust/compile/generics14.rs b/gcc/testsuite/rust/compile/generics14.rs new file mode 100644 index 000000000000..d97fd35a3a42 --- /dev/null +++ b/gcc/testsuite/rust/compile/generics14.rs @@ -0,0 +1 @@ +struct Foo; // { dg-error "invalid order for generic parameters: lifetime parameters must be declared prior to type and const parameters" } From ab254f8cd6f9ce657bd6f2f807973e426ec51162 Mon Sep 17 00:00:00 2001 From: Yap Zhi Heng Date: Sun, 26 Oct 2025 11:13:25 +0800 Subject: [PATCH 04/14] gccrs: Fix `RangePattern` negative literal bounds being treated as positive GIMPLE output for compile/issue-4242.rs: ... x = 1; RUSTTMP.2 = x; _1 = RUSTTMP.2 >= -55; _2 = RUSTTMP.2 < 0; _3 = _1 & _2; if (_3 != 0) goto ; else goto ; : { RUSTTMP.1 = 2; goto ; } : _4 = RUSTTMP.2 >= -99; _5 = RUSTTMP.2 < -55; _6 = _4 & _5; if (_6 != 0) goto ; else goto ; : { RUSTTMP.1 = 3; goto ; } ... gcc/rust/ChangeLog: * backend/rust-compile-pattern.cc (compile_range_pattern_bound): Set litexpr to negative if has_minus is present in the RangePatternBoundLiteral param. Signed-off-by: Yap Zhi Heng --- gcc/rust/backend/rust-compile-pattern.cc | 2 ++ gcc/testsuite/rust/compile/issue-4242.rs | 10 ++++++++++ gcc/testsuite/rust/execute/torture/issue-4242.rs | 11 +++++++++++ 3 files changed, 23 insertions(+) create mode 100644 gcc/testsuite/rust/compile/issue-4242.rs create mode 100644 gcc/testsuite/rust/execute/torture/issue-4242.rs diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index 3a983e9bc887..c29359aebe96 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -121,6 +121,8 @@ compile_range_pattern_bound (HIR::RangePatternBound &bound, HIR::LiteralExpr litexpr (mappings, ref.get_literal (), locus, std::vector ()); + if (ref.get_has_minus()) + litexpr.set_negative(); result = CompileExpr::Compile (litexpr, ctx); } diff --git a/gcc/testsuite/rust/compile/issue-4242.rs b/gcc/testsuite/rust/compile/issue-4242.rs new file mode 100644 index 000000000000..ecbe258cec66 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4242.rs @@ -0,0 +1,10 @@ +#![feature(exclusive_range_pattern)] + +fn main() { + let x = 1; + + match x { + -55..0 => 2, + -99..-55 => 3, + }; +} \ No newline at end of file diff --git a/gcc/testsuite/rust/execute/torture/issue-4242.rs b/gcc/testsuite/rust/execute/torture/issue-4242.rs new file mode 100644 index 000000000000..867adc98e309 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-4242.rs @@ -0,0 +1,11 @@ +#![feature(exclusive_range_pattern)] + +fn main() -> i32 { + let x = -77; + + match x { + -55..99 => 1, + -99..-55 => 0, // the correct case + _ => 1, + } +} \ No newline at end of file From 4192f5971f93413a9ee40a530ec40df0820ce3e4 Mon Sep 17 00:00:00 2001 From: Yap Zhi Heng Date: Mon, 20 Oct 2025 14:01:40 +0800 Subject: [PATCH 05/14] gccrs: Implement E0579 error checking in RangePattern compilation Checks whether upper bound of range is not lower or equal to the lower bound. gcc/rust/ChangeLog: * backend/rust-compile-pattern.cc(compilePatternCheckExpr::visit(RangePattern)): Add E0579 check to ensure that lower bound is always below upper bound. Signed-off-by: Yap Zhi Heng --- gcc/rust/backend/rust-compile-pattern.cc | 28 ++++++++++++++++++++++-- gcc/testsuite/rust/compile/issue-3659.rs | 10 +++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/rust/compile/issue-3659.rs diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index c29359aebe96..708a824ad4d5 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -121,8 +121,8 @@ compile_range_pattern_bound (HIR::RangePatternBound &bound, HIR::LiteralExpr litexpr (mappings, ref.get_literal (), locus, std::vector ()); - if (ref.get_has_minus()) - litexpr.set_negative(); + if (ref.get_has_minus ()) + litexpr.set_negative (); result = CompileExpr::Compile (litexpr, ctx); } @@ -163,6 +163,30 @@ CompilePatternCheckExpr::visit (HIR::RangePattern &pattern) pattern.get_mappings (), pattern.get_locus (), ctx); + rust_assert ( + (TREE_CODE (upper) == REAL_CST && TREE_CODE (lower) == REAL_CST) + || (TREE_CODE (upper) == INTEGER_CST && TREE_CODE (lower) == INTEGER_CST)); + + bool error_E0579 = false; + if (TREE_CODE (upper) == REAL_CST) + { + REAL_VALUE_TYPE upper_r = TREE_REAL_CST (upper); + REAL_VALUE_TYPE lower_r = TREE_REAL_CST (lower); + if (real_compare (GE_EXPR, &lower_r, &upper_r)) + error_E0579 = true; + } + else if (TREE_CODE (upper) == INTEGER_CST) + { + auto upper_wi = wi::to_wide (upper).to_shwi (); + auto lower_wi = wi::to_wide (lower).to_shwi (); + if (lower_wi >= upper_wi) + error_E0579 = true; + } + + if (error_E0579) + rust_error_at (pattern.get_locus (), ErrorCode::E0579, + "lower range bound must be less than upper"); + ComparisonOperator upper_cmp = pattern.is_inclusive_range () ? ComparisonOperator::LESS_OR_EQUAL : ComparisonOperator::LESS_THAN; diff --git a/gcc/testsuite/rust/compile/issue-3659.rs b/gcc/testsuite/rust/compile/issue-3659.rs new file mode 100644 index 000000000000..ffbc63481b61 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3659.rs @@ -0,0 +1,10 @@ +#![feature(exclusive_range_pattern)] + +fn main() { + let x = 3; + + match x { + 0..-1 => 2, // { dg-error "lower range bound must be less than upper .E0579." } + _ => 3, + }; +} From 8346ee65da0b61146b832ec2b1501650597671a0 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Mon, 3 Nov 2025 16:48:56 +0000 Subject: [PATCH 06/14] gccrs: Add support for binding const generic values to paths Const generics bind values which can be accessed like a normal path but the difference is that they can be true expression values not just type paths. This patch adds support to resolving a method inference which passes a generic value into the method and fixes some missed bugs along the way. The tricky part was that there is a case where in the return position of a method returning a const param type vs the type of the method there is a special case in the unify rules so that we unify the specified type of the const param type not the const param itself. gcc/rust/ChangeLog: * backend/rust-compile-resolve-path.cc: handle const param values * typecheck/rust-hir-type-check-item.cc: generate const infer vars when required * typecheck/rust-type-util.cc (unify_site_and): handle a null param cleanup * typecheck/rust-tyty-util.cc (TyVar::get_implicit_const_infer_var): helper interface * typecheck/rust-tyty-util.h: update header prototypes * typecheck/rust-tyty.cc (BaseType::is_concrete): correctly handle const types (ConstParamType::get_name): emit the specified type (ConstParamType::is_equal): fix recursion loop * typecheck/rust-unify.cc (UnifyRules::go): const infer vars need cleanup too * typecheck/rust-unify.h: support base generics gcc/testsuite/ChangeLog: * rust/execute/torture/const-generics-2.rs: New test. Signed-off-by: Philip Herron --- gcc/rust/backend/rust-compile-resolve-path.cc | 21 ++++--- .../typecheck/rust-hir-type-check-item.cc | 22 +++++-- gcc/rust/typecheck/rust-type-util.cc | 10 +-- gcc/rust/typecheck/rust-tyty-util.cc | 7 ++- gcc/rust/typecheck/rust-tyty-util.h | 3 +- gcc/rust/typecheck/rust-tyty.cc | 36 ++++++++--- gcc/rust/typecheck/rust-unify.cc | 62 ++++++++++++++----- gcc/rust/typecheck/rust-unify.h | 8 +-- .../rust/execute/torture/const-generics-2.rs | 20 ++++++ 9 files changed, 141 insertions(+), 48 deletions(-) create mode 100644 gcc/testsuite/rust/execute/torture/const-generics-2.rs diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc index c33d0b072d06..5f306620f7b5 100644 --- a/gcc/rust/backend/rust-compile-resolve-path.cc +++ b/gcc/rust/backend/rust-compile-resolve-path.cc @@ -132,10 +132,8 @@ ResolvePathRef::resolve_with_node_id ( tl::optional hid = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id); if (!hid.has_value ()) - { - rust_error_at (expr_locus, "reverse call path lookup failure"); - return error_mark_node; - } + return error_mark_node; + auto ref = hid.value (); // might be a constant @@ -189,6 +187,17 @@ ResolvePathRef::resolve_with_node_id ( } } + // possibly a const expr value + if (lookup->get_kind () == TyTy::TypeKind::CONST) + { + auto d = lookup->destructure (); + rust_assert (d->get_kind () == TyTy::TypeKind::CONST); + auto c = d->as_const_type (); + rust_assert (c->const_kind () == TyTy::BaseConstType::ConstKind::Value); + auto val = static_cast (c); + return val->get_value (); + } + // Handle unit struct tree resolved_item = error_mark_node; if (lookup->get_kind () == TyTy::TypeKind::ADT) @@ -203,9 +212,7 @@ ResolvePathRef::resolve_with_node_id ( resolved_item = query_compile (ref, lookup, final_segment, mappings, expr_locus, is_qualified_path); if (resolved_item != error_mark_node) - { - TREE_USED (resolved_item) = 1; - } + TREE_USED (resolved_item) = 1; return resolved_item; } diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc index 4987c88ab706..ee5c4e98fba1 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc @@ -112,17 +112,27 @@ TypeCheckItem::ResolveImplBlockSelfWithInference ( std::vector args; for (auto &p : substitutions) { - if (p.needs_substitution ()) + auto param = p.get_param_ty (); + if (!p.needs_substitution ()) { - TyTy::TyVar infer_var = TyTy::TyVar::get_implicit_infer_var (locus); - args.emplace_back (&p, infer_var.get_tyty ()); + auto resolved = param->destructure (); + args.emplace_back (&p, resolved); + + continue; + } + + TyTy::BaseType *argument = nullptr; + if (param->get_kind () == TyTy::TypeKind::CONST) + { + auto i = TyTy::TyVar::get_implicit_const_infer_var (locus); + argument = i.get_tyty (); } else { - auto param = p.get_param_ty (); - auto resolved = param->destructure (); - args.emplace_back (&p, resolved); + auto i = TyTy::TyVar::get_implicit_infer_var (locus); + argument = i.get_tyty (); } + args.emplace_back (&p, argument); } // create argument mappings diff --git a/gcc/rust/typecheck/rust-type-util.cc b/gcc/rust/typecheck/rust-type-util.cc index 6f30ebf49e9b..a6b996658483 100644 --- a/gcc/rust/typecheck/rust-type-util.cc +++ b/gcc/rust/typecheck/rust-type-util.cc @@ -221,13 +221,13 @@ unify_site_and (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, } else if (cleanup) { - // FIXME - // reset the get_next_hir_id - for (auto &i : infers) { - i.param->set_ref (i.pref); - i.param->set_ty_ref (i.ptyref); + if (i.param != nullptr) + { + i.param->set_ref (i.pref); + i.param->set_ty_ref (i.ptyref); + } // remove the inference variable context.clear_type (i.infer); diff --git a/gcc/rust/typecheck/rust-tyty-util.cc b/gcc/rust/typecheck/rust-tyty-util.cc index 72761d9842b3..b780eaac7433 100644 --- a/gcc/rust/typecheck/rust-tyty-util.cc +++ b/gcc/rust/typecheck/rust-tyty-util.cc @@ -62,14 +62,15 @@ TyVar::get_implicit_infer_var (location_t locus) } TyVar -TyVar::get_implicit_const_infer_var (location_t locus) +TyVar::get_implicit_const_infer_var (location_t locus, TyVar *implicit_type) { auto &mappings = Analysis::Mappings::get (); auto context = Resolver::TypeCheckContext::get (); - TyVar ty_infer = get_implicit_infer_var (locus); + TyVar it = (implicit_type != nullptr) ? *implicit_type + : get_implicit_infer_var (locus); HirId next = mappings.get_next_hir_id (); - auto infer = new ConstInferType (ty_infer.get_tyty (), next, next, {}); + auto infer = new ConstInferType (it.get_tyty (), next, next, {}); context->insert_implicit_type (infer->get_ref (), infer); mappings.insert_location (infer->get_ref (), locus); diff --git a/gcc/rust/typecheck/rust-tyty-util.h b/gcc/rust/typecheck/rust-tyty-util.h index 26101fd4d932..b132487eb5eb 100644 --- a/gcc/rust/typecheck/rust-tyty-util.h +++ b/gcc/rust/typecheck/rust-tyty-util.h @@ -43,7 +43,8 @@ class TyVar static TyVar get_implicit_infer_var (location_t locus); - static TyVar get_implicit_const_infer_var (location_t locus); + static TyVar get_implicit_const_infer_var (location_t locus, + TyVar *implicit_type = nullptr); static TyVar subst_covariant_var (TyTy::BaseType *orig, TyTy::BaseType *subst); diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index da5c35049faa..480e244fd38e 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -785,11 +785,18 @@ BaseType::is_concrete () const { const TyTy::BaseType *x = destructure (); - if (x->is () || x->is () - || x->is ()) + if (x->is () || x->is ()) { return false; } + else if (x->get_kind () == TyTy::TypeKind::CONST) + { + auto p = x->as_const_type (); + if (p->const_kind () == BaseConstType::ConstKind::Decl) + return false; + + return true; + } // placeholder is a special case for this case when it is not resolvable // it means we its just an empty placeholder associated type which is // concrete @@ -3633,9 +3640,8 @@ ConstParamType::get_name () const return get_symbol (); BaseType *lookup = resolve (); - // Avoid infinite recursion if resolve() returns this same type if (lookup == this->as_base_type ()) - return get_symbol (); + return get_symbol () + ":" + get_specified_type ()->get_name (); return lookup->get_name (); } @@ -3660,9 +3666,25 @@ ConstParamType::is_equal (const BaseType &other) const return false; if (can_resolve ()) - return Resolver::types_compatable (TyTy::TyWithLocation (resolve ()), - TyTy::TyWithLocation (other2.resolve ()), - ident.locus, false); + { + // Compare the resolved ty_ref values to avoid infinite recursion + // through types_compatable/unification + BaseType *lhs = resolve (); + BaseType *rhs = other2.resolve (); + + // If they resolve to the same type (same ty_ref), they're equal + if (lhs->get_ty_ref () == rhs->get_ty_ref ()) + return true; + + // Otherwise check if the resolved types are equal + // Avoid recursion by checking if we'd be comparing ConstParamTypes again + if (lhs->get_kind () == TypeKind::CONST + && lhs->as_const_type ()->const_kind () + == BaseConstType::ConstKind::Decl) + return false; // Would cause recursion, so not equal + + return lhs->is_equal (*rhs); + } return get_symbol ().compare (other2.get_symbol ()) == 0; } diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc index 43dd6dca6173..36dbc0e187e1 100644 --- a/gcc/rust/typecheck/rust-unify.cc +++ b/gcc/rust/typecheck/rust-unify.cc @@ -18,8 +18,8 @@ #include "rust-unify.h" #include "fold-const.h" +#include "rust-tyty-util.h" #include "rust-tyty.h" -#include "tree.h" namespace Rust { namespace Resolver { @@ -302,35 +302,67 @@ UnifyRules::go () else if (ltype->get_kind () == TyTy::TypeKind::CONST && rtype->get_kind () == TyTy::TypeKind::CONST) { - const auto &lhs = *ltype->as_const_type (); - const auto &rhs = *rtype->as_const_type (); + auto lhs = ltype->as_const_type (); + auto rhs = rtype->as_const_type (); bool both_are_decls - = lhs.const_kind () == TyTy::BaseConstType::ConstKind::Decl - && rhs.const_kind () == TyTy::BaseConstType::ConstKind::Decl; + = lhs->const_kind () == TyTy::BaseConstType::ConstKind::Decl + && rhs->const_kind () == TyTy::BaseConstType::ConstKind::Decl; bool have_decls - = lhs.const_kind () == TyTy::BaseConstType::ConstKind::Decl - || rhs.const_kind () == TyTy::BaseConstType::ConstKind::Decl; + = lhs->const_kind () == TyTy::BaseConstType::ConstKind::Decl + || rhs->const_kind () == TyTy::BaseConstType::ConstKind::Decl; if (have_decls && !both_are_decls) { - if (lhs.const_kind () == TyTy::BaseConstType::ConstKind::Decl) + if (lhs->const_kind () == TyTy::BaseConstType::ConstKind::Decl) { - TyTy::TyVar iv = TyTy::TyVar::get_implicit_const_infer_var ( - lhs.as_base_type ()->get_locus ()); - ltype = iv.get_tyty (); + auto l = lhs->as_base_type ()->get_locus (); + auto p = static_cast (lhs); + auto it = TyTy::TyVar::get_implicit_infer_var (l); + auto iv = TyTy::TyVar::get_implicit_const_infer_var (l, &it); + auto ivt = iv.get_tyty (); + + infers.emplace_back (0, 0, nullptr, it.get_tyty ()); + infers.emplace_back (ltype->get_ref (), ltype->get_ty_ref (), + p, ivt); + + ltype = ivt; + p->set_ty_ref (ltype->get_ref ()); } - else if (rhs.const_kind () + else if (rhs->const_kind () == TyTy::BaseConstType::ConstKind::Decl) { - TyTy::TyVar iv = TyTy::TyVar::get_implicit_const_infer_var ( - rhs.as_base_type ()->get_locus ()); - rtype = iv.get_tyty (); + auto l = rhs->as_base_type ()->get_locus (); + auto p = static_cast (rhs); + auto it = TyTy::TyVar::get_implicit_infer_var (l); + auto iv = TyTy::TyVar::get_implicit_const_infer_var (l, &it); + auto ivt = iv.get_tyty (); + + infers.emplace_back (0, 0, nullptr, it.get_tyty ()); + infers.emplace_back (rtype->get_ref (), rtype->get_ty_ref (), + p, ivt); + + rtype = ivt; + p->set_ty_ref (rtype->get_ref ()); } } } } + if (ltype->get_kind () != TyTy::TypeKind::CONST + && rtype->get_kind () == TyTy::TypeKind::CONST) + { + auto *rc = rtype->as_const_type (); + rtype = rc->get_specified_type (); + } + + if (ltype->get_kind () == TyTy::TypeKind::CONST + && rtype->get_kind () != TyTy::TypeKind::CONST) + { + auto *lc = ltype->as_const_type (); + ltype = lc->get_specified_type (); + } + switch (ltype->get_kind ()) { case TyTy::INFER: diff --git a/gcc/rust/typecheck/rust-unify.h b/gcc/rust/typecheck/rust-unify.h index 4bed24c924f8..2b772feb8b92 100644 --- a/gcc/rust/typecheck/rust-unify.h +++ b/gcc/rust/typecheck/rust-unify.h @@ -30,15 +30,15 @@ class UnifyRules public: struct InferenceSite { - InferenceSite (HirId pref, HirId ptyref, TyTy::ParamType *param, - TyTy::InferType *infer) + InferenceSite (HirId pref, HirId ptyref, TyTy::BaseGeneric *param, + TyTy::BaseType *infer) : pref (pref), ptyref (ptyref), param (param), infer (infer) {} HirId pref; HirId ptyref; - TyTy::ParamType *param; - TyTy::InferType *infer; + TyTy::BaseGeneric *param; + TyTy::BaseType *infer; }; struct CommitSite { diff --git a/gcc/testsuite/rust/execute/torture/const-generics-2.rs b/gcc/testsuite/rust/execute/torture/const-generics-2.rs new file mode 100644 index 000000000000..cf92953a37ae --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/const-generics-2.rs @@ -0,0 +1,20 @@ +#[lang = "sized"] +trait Sized {} + +trait Magic { + fn magic(&self) -> usize; +} + +struct Foo; + +impl Magic for Foo { + fn magic(&self) -> usize { + N + } +} + +fn main() -> i32 { + let f = Foo::<7> {}; + let n = f.magic(); + n as i32 - 7 +} From 4ee737035b55f6039c1014472b82832215c5b62e Mon Sep 17 00:00:00 2001 From: Lucas Ly Ba Date: Thu, 6 Nov 2025 16:53:00 +0000 Subject: [PATCH 07/14] gccrs: fix error multiple cfg predicates gcc/rust/ChangeLog: * ast/rust-ast.cc (Attribute::check_cfg_predicate): Make error. gcc/testsuite/ChangeLog: * rust/compile/issue-4267.rs: New test. Signed-off-by: Lucas Ly Ba --- gcc/rust/ast/rust-ast.cc | 8 ++++++++ gcc/testsuite/rust/compile/issue-4267.rs | 3 +++ 2 files changed, 11 insertions(+) create mode 100644 gcc/testsuite/rust/compile/issue-4267.rs diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc index 337a338f9a39..5bced483adb4 100644 --- a/gcc/rust/ast/rust-ast.cc +++ b/gcc/rust/ast/rust-ast.cc @@ -4185,6 +4185,14 @@ Attribute::check_cfg_predicate (const Session &session) const "malformed % attribute input"); return false; } + + if (string_path == Values::Attributes::CFG + && meta_item.get_items ().size () != 1) + { + rust_error_at (path.get_locus (), "multiple %qs predicates are specified", + path.as_string ().c_str ()); + return false; + } return meta_item.get_items ().front ()->check_cfg_predicate (session); } diff --git a/gcc/testsuite/rust/compile/issue-4267.rs b/gcc/testsuite/rust/compile/issue-4267.rs new file mode 100644 index 000000000000..f507748c6944 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4267.rs @@ -0,0 +1,3 @@ +#[cfg(a,a)] +// { dg-error "multiple .cfg. predicates are specified" "" { target *-*-* } .-1 } +fn a(){} From 6abcb83ecdf7b8c66f0c740411008a2ca001feba Mon Sep 17 00:00:00 2001 From: Lucas Ly Ba Date: Thu, 6 Nov 2025 14:57:45 +0000 Subject: [PATCH 08/14] gccrs: fix segfault with empty cfg attribute gcc/rust/ChangeLog: * ast/rust-ast.cc (Attribute::check_cfg_predicate): add cfg path in condition gcc/testsuite/ChangeLog: * rust/compile/issue-4261.rs: New test. Signed-off-by: Lucas Ly Ba --- gcc/rust/ast/rust-ast.cc | 7 ++++--- gcc/testsuite/rust/compile/issue-4261.rs | 3 +++ 2 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/rust/compile/issue-4261.rs diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc index 5bced483adb4..7c6a1d215af8 100644 --- a/gcc/rust/ast/rust-ast.cc +++ b/gcc/rust/ast/rust-ast.cc @@ -4179,10 +4179,11 @@ Attribute::check_cfg_predicate (const Session &session) const auto &meta_item = static_cast (*attr_input); if (meta_item.get_items ().empty () - && string_path == Values::Attributes::CFG_ATTR) + && (string_path == Values::Attributes::CFG + || string_path == Values::Attributes::CFG_ATTR)) { - rust_error_at (path.get_locus (), - "malformed % attribute input"); + rust_error_at (path.get_locus (), "malformed %<%s%> attribute input", + string_path.c_str ()); return false; } diff --git a/gcc/testsuite/rust/compile/issue-4261.rs b/gcc/testsuite/rust/compile/issue-4261.rs new file mode 100644 index 000000000000..32beafade547 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4261.rs @@ -0,0 +1,3 @@ +#[cfg()] +// { dg-error "malformed .cfg. attribute input" "" { target *-*-* } .-1 } +fn a() {} From 9d008cded29b633e0e2763a602a5bec5bf5ae83a Mon Sep 17 00:00:00 2001 From: Lucas Ly Ba Date: Thu, 6 Nov 2025 16:26:12 +0000 Subject: [PATCH 09/14] gccrs: fix cfg attribute error with literal predicate gcc/rust/ChangeLog: * ast/rust-ast.cc (MetaItemLitExpr::check_cfg_predicate): Make error. gcc/testsuite/ChangeLog: * rust/compile/issue-4222.rs: New test. Signed-off-by: Lucas Ly Ba --- gcc/rust/ast/rust-ast.cc | 3 +++ gcc/testsuite/rust/compile/issue-4222.rs | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 gcc/testsuite/rust/compile/issue-4222.rs diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc index 7c6a1d215af8..6d37ef7e22fb 100644 --- a/gcc/rust/ast/rust-ast.cc +++ b/gcc/rust/ast/rust-ast.cc @@ -3834,6 +3834,9 @@ MetaItemLitExpr::check_cfg_predicate (const Session &) const { /* as far as I can tell, a literal expr can never be a valid cfg body, so * false */ + rust_error_at (this->get_locus (), "'%s' predicate key cannot be a literal", + this->as_string ().c_str ()); + return false; } diff --git a/gcc/testsuite/rust/compile/issue-4222.rs b/gcc/testsuite/rust/compile/issue-4222.rs new file mode 100644 index 000000000000..b829c6f6f546 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4222.rs @@ -0,0 +1,3 @@ +#![cfg(false)] +// { dg-error ".false. predicate key cannot be a literal" "" { target *-*-* } .-1 } +fn a() {} From 86d3a33e8aab786e81ab7e0413aadef3b8e8765a Mon Sep 17 00:00:00 2001 From: Lucas Ly Ba Date: Mon, 13 Oct 2025 11:01:54 +0000 Subject: [PATCH 10/14] gccrs: fix ICE on missing pattern in while loop Adds a proper check for missing patterns in while expressions. Fixes Rust-GCC#4162 gcc/rust/ChangeLog: * parse/rust-parse-impl.h(Parser::parse_while_let_loop_expr): Add check for missing pattern. gcc/testsuite/ChangeLog: * rust/compile/issue-4162.rs: New test. Signed-off-by: Lucas Ly Ba --- gcc/rust/parse/rust-parse-impl.h | 9 ++++++++- gcc/testsuite/rust/compile/issue-4162.rs | 9 +++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/rust/compile/issue-4162.rs diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index 62831ebbf10e..64554f5e9e49 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -8234,7 +8234,14 @@ Parser::parse_while_let_loop_expr ( // parse predicate patterns std::vector> predicate_patterns = parse_match_arm_patterns (EQUAL); - // TODO: have to ensure that there is at least 1 pattern? + // ensure that there is at least 1 pattern + if (predicate_patterns.empty ()) + { + Error error (lexer.peek_token ()->get_locus (), + "should be at least 1 pattern"); + add_error (std::move (error)); + return nullptr; + } if (!skip_token (EQUAL)) { diff --git a/gcc/testsuite/rust/compile/issue-4162.rs b/gcc/testsuite/rust/compile/issue-4162.rs new file mode 100644 index 000000000000..c82bac611d3e --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4162.rs @@ -0,0 +1,9 @@ +pub fn main() { + while let = 5 + // { dg-error "should be at least 1 pattern" "" { target *-*-* } .-1 } + // { dg-error "failed to parse statement or expression in block expression" "" { target *-*-* } .-2 } + // { dg-error "unrecognised token .=. for start of item" "" { target *-*-* } .-3 } + // { dg-error "failed to parse item in crate" "" { target *-*-* } .-4 } + {} +} + From 77393a3d2c6109f5dab16583ab7be5299d8575ad Mon Sep 17 00:00:00 2001 From: Lucas Ly Ba Date: Mon, 3 Nov 2025 16:28:56 +0000 Subject: [PATCH 11/14] gccrs: make invalid inner attributes show error gcc/rust/ChangeLog: * ast/rust-ast.cc (Attribute::is_derive): Change is_derive method with its valid path. * util/rust-attribute-values.h: Delete redudant derive attribute. * util/rust-attributes.cc (AttributeChecker::check_inner_attribute): Helper method for check_inner_attributes (AttributeChecker::check_inner_attributes): Implement method for errors check. * util/rust-attributes.h: Add methods above in header. gcc/testsuite/ChangeLog: * rust/compile/issue-4212.rs: * rust/compile/issue-4219.rs: New test. Signed-off-by: Lucas Ly Ba --- gcc/rust/ast/rust-ast.cc | 2 +- gcc/rust/util/rust-attribute-values.h | 2 -- gcc/rust/util/rust-attributes.cc | 43 ++++++++++++++---------- gcc/rust/util/rust-attributes.h | 8 +++-- gcc/testsuite/rust/compile/issue-4212.rs | 2 +- gcc/testsuite/rust/compile/issue-4219.rs | 5 +++ 6 files changed, 37 insertions(+), 25 deletions(-) create mode 100644 gcc/testsuite/rust/compile/issue-4219.rs diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc index 6d37ef7e22fb..f3ad2fe5da05 100644 --- a/gcc/rust/ast/rust-ast.cc +++ b/gcc/rust/ast/rust-ast.cc @@ -248,7 +248,7 @@ Attribute::as_string () const bool Attribute::is_derive () const { - return has_attr_input () && get_path () == Values::Attributes::DERIVE; + return has_attr_input () && get_path () == Values::Attributes::DERIVE_ATTR; } /** diff --git a/gcc/rust/util/rust-attribute-values.h b/gcc/rust/util/rust-attribute-values.h index a22664a1c48f..0f35f56f798e 100644 --- a/gcc/rust/util/rust-attribute-values.h +++ b/gcc/rust/util/rust-attribute-values.h @@ -49,8 +49,6 @@ class Attributes static constexpr auto &PROC_MACRO_DERIVE = "proc_macro_derive"; static constexpr auto &PROC_MACRO_ATTRIBUTE = "proc_macro_attribute"; - static constexpr auto &DERIVE = "derive"; - static constexpr auto &TARGET_FEATURE = "target_feature"; // From now on, these are reserved by the compiler and gated through // #![feature(rustc_attrs)] diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc index 9621100cc952..70f26e7ce361 100644 --- a/gcc/rust/util/rust-attributes.cc +++ b/gcc/rust/util/rust-attributes.cc @@ -90,8 +90,6 @@ static const BuiltinAttrDefinition __definitions[] {Attrs::PROC_MACRO, EXPANSION}, {Attrs::PROC_MACRO_DERIVE, EXPANSION}, {Attrs::PROC_MACRO_ATTRIBUTE, EXPANSION}, - - {Attrs::DERIVE, EXPANSION}, // FIXME: This is not implemented yet, see // https://github.com/Rust-GCC/gccrs/issues/1475 {Attrs::TARGET_FEATURE, CODE_GENERATION}, @@ -101,7 +99,6 @@ static const BuiltinAttrDefinition __definitions[] {Attrs::RUSTC_INHERIT_OVERFLOW_CHECKS, CODE_GENERATION}, {Attrs::STABLE, STATIC_ANALYSIS}, {Attrs::UNSTABLE, STATIC_ANALYSIS}, - // assuming we keep these for static analysis {Attrs::RUSTC_PROMOTABLE, CODE_GENERATION}, {Attrs::RUSTC_CONST_STABLE, STATIC_ANALYSIS}, @@ -114,23 +111,22 @@ static const BuiltinAttrDefinition __definitions[] {Attrs::RUSTC_RESERVATION_IMPL, TYPE_CHECK}, {Attrs::RUSTC_PAREN_SUGAR, TYPE_CHECK}, {Attrs::RUSTC_NONNULL_OPTIMIZATION_GUARANTEED, TYPE_CHECK}, - {Attrs::RUSTC_LAYOUT_SCALAR_VALID_RANGE_START, CODE_GENERATION}, - // TODO: be careful about calling functions marked with this? {Attrs::RUSTC_ARGS_REQUIRED_CONST, CODE_GENERATION}, - {Attrs::PRELUDE_IMPORT, NAME_RESOLUTION}, - {Attrs::RUSTC_DIAGNOSTIC_ITEM, STATIC_ANALYSIS}, {Attrs::RUSTC_ON_UNIMPLEMENTED, STATIC_ANALYSIS}, - {Attrs::FUNDAMENTAL, TYPE_CHECK}, {Attrs::NON_EXHAUSTIVE, TYPE_CHECK}, {Attrs::RUSTFMT, EXTERNAL}, - {Attrs::TEST, CODE_GENERATION}}; +static const std::set __outer_attributes + = {Attrs::INLINE, Attrs::DERIVE_ATTR, Attrs::ALLOW_INTERNAL_UNSTABLE, + Attrs::LANG, Attrs::REPR, Attrs::PATH, + Attrs::TARGET_FEATURE, Attrs::TEST}; + BuiltinAttributeMappings * BuiltinAttributeMappings::get () { @@ -326,6 +322,26 @@ check_proc_macro_non_root (AST::AttrVec attributes, location_t loc) } } +void +AttributeChecker::check_inner_attribute (const AST::Attribute &attribute) +{ + BuiltinAttrDefinition result; + + if (!is_builtin (attribute, result)) + return; + + if (__outer_attributes.find (result.name) != __outer_attributes.end ()) + rust_error_at (attribute.get_locus (), + "attribute cannot be used at crate level"); +} + +void +AttributeChecker::check_inner_attributes (const AST::AttrVec &attributes) +{ + for (auto &attr : attributes) + check_inner_attribute (attr); +} + void AttributeChecker::check_attribute (const AST::Attribute &attribute) { @@ -356,15 +372,6 @@ AttributeChecker::check_attribute (const AST::Attribute &attribute) check_doc_attribute (attribute); } -void -AttributeChecker::check_inner_attributes (const AST::AttrVec &attributes) -{ - for (auto &attr : attributes) - if (attr.is_derive ()) - rust_error_at (attr.get_locus (), - "derive attribute cannot be used at crate level"); -} - void AttributeChecker::check_attributes (const AST::AttrVec &attributes) { diff --git a/gcc/rust/util/rust-attributes.h b/gcc/rust/util/rust-attributes.h index b10a0806530b..f4a2d389c3d2 100644 --- a/gcc/rust/util/rust-attributes.h +++ b/gcc/rust/util/rust-attributes.h @@ -102,12 +102,14 @@ class AttributeChecker : public AST::DefaultASTVisitor private: using AST::DefaultASTVisitor::visit; + + /* Check the validity of an inner attribute */ + void check_inner_attribute (const AST::Attribute &attribute); + /* Check the validy of all inner attributes */ + void check_inner_attributes (const AST::AttrVec &attributes); /* Check the validity of a given attribute */ void check_attribute (const AST::Attribute &attribute); - /* Check the validity of all given attributes */ - - void check_inner_attributes (const AST::AttrVec &attributes); void check_attributes (const AST::AttrVec &attributes); // rust-ast.h diff --git a/gcc/testsuite/rust/compile/issue-4212.rs b/gcc/testsuite/rust/compile/issue-4212.rs index e068e458c24f..e7bf113d7aad 100644 --- a/gcc/testsuite/rust/compile/issue-4212.rs +++ b/gcc/testsuite/rust/compile/issue-4212.rs @@ -1,5 +1,5 @@ #![derive(PartialOrd, PartialEq)] -// { dg-error "derive attribute cannot be used at crate level" "" { target *-*-* } .-1 } +// { dg-error "attribute cannot be used at crate level" "" { target *-*-* } .-1 } pub fn check_ge(a: i32, b: i32) -> bool { a >= b } diff --git a/gcc/testsuite/rust/compile/issue-4219.rs b/gcc/testsuite/rust/compile/issue-4219.rs new file mode 100644 index 000000000000..d6e70e9a7264 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4219.rs @@ -0,0 +1,5 @@ +#![inline] +// { dg-error "attribute cannot be used at crate level" "" { target *-*-* } .-1 } +pub fn check_ge(a: i32, b: i32) -> bool { + a >= b +} From 73ed68d698d86e5e8b67832030381f52bbd82e2f Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Sun, 9 Nov 2025 15:49:09 +0000 Subject: [PATCH 12/14] gccrs: Fix const generics handling on array types When we were processing generic const param types on arrays the size type was overriding the const param decl because of a hirid reference mismatch Fixes Rust-GCC#3879 gcc/rust/ChangeLog: * typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit): fix mappings gcc/testsuite/ChangeLog: * rust/compile/const_generics_18.rs: New test. * rust/compile/const_generics_19.rs: New test. * rust/execute/torture/const-generics-3.rs: New test. * rust/execute/torture/const-generics-4.rs: New test. Signed-off-by: Philip Herron --- .../typecheck/rust-hir-type-check-type.cc | 3 +- .../rust/compile/const_generics_18.rs | 10 +++++ .../rust/compile/const_generics_19.rs | 10 +++++ .../rust/execute/torture/const-generics-3.rs | 13 ++++++ .../rust/execute/torture/const-generics-4.rs | 43 +++++++++++++++++++ 5 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/rust/compile/const_generics_18.rs create mode 100644 gcc/testsuite/rust/compile/const_generics_19.rs create mode 100644 gcc/testsuite/rust/execute/torture/const-generics-3.rs create mode 100644 gcc/testsuite/rust/execute/torture/const-generics-4.rs diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc index 799efc809d51..ca7ef472578a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc @@ -704,7 +704,6 @@ TypeCheckType::visit (HIR::ArrayType &type) TyTy::BaseType *expected_ty = nullptr; bool ok = context->lookup_builtin ("usize", &expected_ty); rust_assert (ok); - context->insert_type (type.get_size_expr ().get_mappings (), expected_ty); TyTy::BaseConstType *const_type = nullptr; if (capacity_type->get_kind () == TyTy::TypeKind::CONST) @@ -745,7 +744,7 @@ TypeCheckType::visit (HIR::ArrayType &type) translated = new TyTy::ArrayType (type.get_mappings ().get_hirid (), type.get_locus (), TyTy::TyVar ( - const_type->as_base_type ()->get_ty_ref ()), + const_type->as_base_type ()->get_ref ()), TyTy::TyVar (element_type->get_ref ())); } diff --git a/gcc/testsuite/rust/compile/const_generics_18.rs b/gcc/testsuite/rust/compile/const_generics_18.rs new file mode 100644 index 000000000000..8bcc26158b44 --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_18.rs @@ -0,0 +1,10 @@ +#[lang = "sized"] +trait Sized {} + +struct Foo; +type Alias = Foo<4>; + +fn main() -> i32 { + let _x: Alias = Foo::<4> {}; + 0 +} diff --git a/gcc/testsuite/rust/compile/const_generics_19.rs b/gcc/testsuite/rust/compile/const_generics_19.rs new file mode 100644 index 000000000000..b0932ae60272 --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_19.rs @@ -0,0 +1,10 @@ +#[lang = "sized"] +trait Sized {} + +struct Foo; +struct Wrapper(T); + +fn main() -> i32 { + let _: Wrapper> = Wrapper(Foo::<3> {}); + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/const-generics-3.rs b/gcc/testsuite/rust/execute/torture/const-generics-3.rs new file mode 100644 index 000000000000..53698bb2dd64 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/const-generics-3.rs @@ -0,0 +1,13 @@ +#[lang = "sized"] +pub trait Sized {} + +fn simd_shuffle(idx: [u32; N]) -> [u32; N] { + idx +} + +fn main() -> i32 { + let a = [1u32, 2, 3, 4]; + let out = simd_shuffle(a); + let _check: [u32; 4] = out; + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/const-generics-4.rs b/gcc/testsuite/rust/execute/torture/const-generics-4.rs new file mode 100644 index 000000000000..bf64f13e6545 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/const-generics-4.rs @@ -0,0 +1,43 @@ +#[lang = "sized"] +trait Sized {} + +#[allow(unused)] +macro_rules! simd_shuffle { + ($x:expr, $y:expr, $idx:expr $(,)?) => {{ + simd_shuffle( + $x, + $y, + const { + let v: [u32; _] = $idx; + v + }, + ) + }}; +} + +const fn simd_shuffle(_a: [u32; 4], _b: [u32; 4], idx: [u32; 4]) -> [u32; 4] { + idx +} + +fn main() -> i32 { + let a = [1, 2, 3, 4]; + let b = [5, 6, 7, 8]; + let indices = [3, 2, 1, 0]; + + let result: [u32; 4] = simd_shuffle!(a, b, indices); + + if result[0] != 3 { + return 1; + } + if result[1] != 2 { + return 2; + } + if result[2] != 1 { + return 3; + } + if result[3] != 0 { + return 4; + } + + 0 +} From a5ca87cb1e809ae921325768515f519bdb1168a7 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Sun, 9 Nov 2025 20:28:50 +0000 Subject: [PATCH 13/14] gccrs: Support generic constant impl items Impl items can have constants defined which could in turn be generic this was not supported by gccrs and missed. So for example: impl Foo { const MAGIC: usize = mem::size_of::(); } This is a normal type parameter but in order to setup the generics we need to create a synthetic TyTy::FnType so we can bind the parent's impl generics to the type system and it just works like any other generic item at that point. Then for example we have: impl Foo { const VALUE: usize = N; } Again we consistently bind the this const generic parameter the same way so the lazy evaluation of the generic can take place. gcc/rust/ChangeLog: * backend/rust-compile-item.cc (CompileItem::visit): support the synthetic function consts * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::Resolve): likewise * typecheck/rust-hir-type-check-implitem.cc (TypeCheckImplItem::visit): create the synth * typecheck/rust-tyty.h: new flag for synthetic constant gcc/testsuite/ChangeLog: * rust/execute/torture/const-generics-5.rs: New test. * rust/execute/torture/const-generics-6.rs: New test. * rust/execute/torture/const-generics-7.rs: New test. Signed-off-by: Philip Herron --- gcc/rust/backend/rust-compile-item.cc | 11 ++++++++ .../typecheck/rust-hir-type-check-expr.cc | 20 +++++++++++-- .../typecheck/rust-hir-type-check-implitem.cc | 28 +++++++++++++++++-- gcc/rust/typecheck/rust-tyty.h | 6 ++++ .../rust/execute/torture/const-generics-5.rs | 13 +++++++++ .../rust/execute/torture/const-generics-6.rs | 15 ++++++++++ .../rust/execute/torture/const-generics-7.rs | 22 +++++++++++++++ 7 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/rust/execute/torture/const-generics-5.rs create mode 100644 gcc/testsuite/rust/execute/torture/const-generics-6.rs create mode 100644 gcc/testsuite/rust/execute/torture/const-generics-7.rs diff --git a/gcc/rust/backend/rust-compile-item.cc b/gcc/rust/backend/rust-compile-item.cc index b72e70d113ec..d9087104e46a 100644 --- a/gcc/rust/backend/rust-compile-item.cc +++ b/gcc/rust/backend/rust-compile-item.cc @@ -109,6 +109,17 @@ CompileItem::visit (HIR::ConstantItem &constant) // canonical path Resolver::CanonicalPath canonical_path = nr_ctx.to_canonical_path (mappings.get_nodeid ()); + if (constant_type->is ()) + { + if (concrete == nullptr) + return; + + rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::FnType *concrete_fnty = static_cast (concrete); + + concrete_fnty->override_context (); + constant_type = expr_type = concrete_fnty->get_return_type (); + } ctx->push_const_context (); tree const_expr diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index 7885dfcf7463..1c00fd96d949 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -53,10 +53,19 @@ TypeCheckExpr::Resolve (HIR::Expr &expr) if (resolver.infered == nullptr) return new TyTy::ErrorType (expr.get_mappings ().get_hirid ()); - auto ref = expr.get_mappings ().get_hirid (); - resolver.infered->set_ref (ref); + if (resolver.infered->get_kind () != TyTy::TypeKind::CONST) + { + auto ref = expr.get_mappings ().get_hirid (); + resolver.infered->set_ref (ref); + } resolver.context->insert_type (expr.get_mappings (), resolver.infered); + if (auto fn = resolver.infered->try_as ()) + { + if (fn->is_syn_constant ()) + resolver.infered = fn->get_return_type (); + } + return resolver.infered; } @@ -2358,7 +2367,12 @@ bool TypeCheckExpr::validate_arithmetic_type ( const TyTy::BaseType *tyty, HIR::ArithmeticOrLogicalExpr::ExprType expr_type) { - const TyTy::BaseType *type = tyty->destructure (); + auto type = tyty->destructure (); + if (type->get_kind () == TyTy::TypeKind::CONST) + { + auto base_const = type->as_const_type (); + type = base_const->get_specified_type (); + } // https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators // this will change later when traits are added diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc index e7f66327d02d..07fc010b0872 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc @@ -391,8 +391,32 @@ TypeCheckImplItem::visit (HIR::ConstantItem &constant) TyTy::TyWithLocation (type, constant.get_type ().get_locus ()), TyTy::TyWithLocation (expr_type, constant.get_expr ().get_locus ()), constant.get_locus ()); - context->insert_type (constant.get_mappings (), unified); - result = unified; + + if (substitutions.empty ()) + { + context->insert_type (constant.get_mappings (), unified); + result = unified; + return; + } + + // special case when this is a generic constant + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + CanonicalPath canonical_path + = nr_ctx.to_canonical_path (constant.get_mappings ().get_nodeid ()); + RustIdent ident{canonical_path, constant.get_locus ()}; + auto fnType = new TyTy::FnType ( + constant.get_mappings ().get_hirid (), + constant.get_mappings ().get_defid (), + constant.get_identifier ().as_string (), ident, + TyTy::FnType::FNTYPE_IS_SYN_CONST_FLAG, ABI::RUST, {}, unified, + std::move (substitutions), + TyTy::SubstitutionArgumentMappings::empty ( + context->get_lifetime_resolver ().get_num_bound_regions ()), + {}); + + context->insert_type (constant.get_mappings (), fnType); + result = fnType; } void diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 3236bf34a592..ed3cd76807cd 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -1050,6 +1050,7 @@ class FnType : public CallableTypeInterface, public SubstitutionRef static const uint8_t FNTYPE_IS_METHOD_FLAG = 0x01; static const uint8_t FNTYPE_IS_EXTERN_FLAG = 0x02; static const uint8_t FNTYPE_IS_VARADIC_FLAG = 0X04; + static const uint8_t FNTYPE_IS_SYN_CONST_FLAG = 0X08; FnType (HirId ref, DefId id, std::string identifier, RustIdent ident, uint8_t flags, ABI abi, std::vector params, BaseType *type, @@ -1111,6 +1112,11 @@ class FnType : public CallableTypeInterface, public SubstitutionRef bool is_variadic () const { return (flags & FNTYPE_IS_VARADIC_FLAG) != 0; } + bool is_syn_constant () const + { + return (flags & FNTYPE_IS_SYN_CONST_FLAG) != 0; + } + DefId get_id () const { return id; } // get the Self type for the method diff --git a/gcc/testsuite/rust/execute/torture/const-generics-5.rs b/gcc/testsuite/rust/execute/torture/const-generics-5.rs new file mode 100644 index 000000000000..fd3c6a2ce151 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/const-generics-5.rs @@ -0,0 +1,13 @@ +#[lang = "sized"] +trait Sized {} + +struct Foo; + +impl Foo { + const VALUE: usize = N; +} + +fn main() -> i32 { + let val = Foo::<7>::VALUE; + val as i32 - 7 +} diff --git a/gcc/testsuite/rust/execute/torture/const-generics-6.rs b/gcc/testsuite/rust/execute/torture/const-generics-6.rs new file mode 100644 index 000000000000..325b58e387d7 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/const-generics-6.rs @@ -0,0 +1,15 @@ +#[lang = "sized"] +trait Sized {} + +struct Foo; + +impl Foo { + const VALUE: usize = N; + const SQUARE: usize = N * N; +} + +fn main() -> i32 { + let a = Foo::<5>::VALUE; // 5 + let b = Foo::<5>::SQUARE; // 25 + (a + b) as i32 - 30 +} diff --git a/gcc/testsuite/rust/execute/torture/const-generics-7.rs b/gcc/testsuite/rust/execute/torture/const-generics-7.rs new file mode 100644 index 000000000000..afba0329a706 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/const-generics-7.rs @@ -0,0 +1,22 @@ +#![feature(intrinsics)] + +#[lang = "sized"] +pub trait Sized {} + +mod mem { + extern "rust-intrinsic" { + #[rustc_const_stable(feature = "const_size_of", since = "1.40.0")] + pub fn size_of() -> usize; + } +} + +struct Foo; + +impl Foo { + const MAGIC: usize = mem::size_of::(); +} + +fn main() -> i32 { + let sz = Foo::::MAGIC; + sz as i32 - 2 +} From aa4982dc50fd5d66f6449718961869cd6441570a Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Sun, 9 Nov 2025 22:05:58 +0000 Subject: [PATCH 14/14] gccrs: Fix segv in errors in type checking an impl item When we typecheck a trait impl block item, at the end we validate it against the trait definition by doing a final unify but if the type check fails on the the impl item it returns NULL here. The other issue was that if we fail to resolve the specified lifetime we return error early, this changes the typechecking to default to an anon lifetime so we can continue typechecking. Fixes Rust-GCC#4188 gcc/rust/ChangeLog: * typecheck/rust-hir-type-check-implitem.cc (TypeCheckImplItemWithTrait::visit): null guard * typecheck/rust-hir-type-check.cc (TraitItemReference::get_type_from_fn): default to anon gcc/testsuite/ChangeLog: * rust/compile/issue-4188.rs: New test. Signed-off-by: Philip Herron --- gcc/rust/typecheck/rust-hir-type-check-implitem.cc | 2 ++ gcc/rust/typecheck/rust-hir-type-check.cc | 11 ++++++----- gcc/testsuite/rust/compile/issue-4188.rs | 13 +++++++++++++ 3 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/rust/compile/issue-4188.rs diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc index 07fc010b0872..83adf2ea761b 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc @@ -582,6 +582,8 @@ TypeCheckImplItemWithTrait::visit (HIR::Function &function) // normal resolution of the item TyTy::BaseType *lookup = TypeCheckImplItem::Resolve (parent, function, self, substitutions); + if (lookup == nullptr) + return; // map the impl item to the associated trait item const auto tref = trait_reference.get (); diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index 64f4314e3151..3215f4348048 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -237,19 +237,20 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const : Mutability::Mut; rust_assert (self_param.has_lifetime ()); + auto region = TyTy::Region::make_anonymous (); auto maybe_region = context->lookup_and_resolve_lifetime ( self_param.get_lifetime ()); - - if (!maybe_region.has_value ()) + if (maybe_region.has_value ()) + region = maybe_region.value (); + else { rust_error_at (self_param.get_locus (), "failed to resolve lifetime"); - return get_error (); } + self_type = new TyTy::ReferenceType ( self_param.get_mappings ().get_hirid (), - TyTy::TyVar (self->get_ref ()), mutability, - maybe_region.value ()); + TyTy::TyVar (self->get_ref ()), mutability, region); } break; diff --git a/gcc/testsuite/rust/compile/issue-4188.rs b/gcc/testsuite/rust/compile/issue-4188.rs new file mode 100644 index 000000000000..32b175dbdb4c --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4188.rs @@ -0,0 +1,13 @@ +trait MemoryUnit { + extern "C" fn read_dword(&'s self) -> u16 {} + // { dg-error {failed to resolve lifetime} "" { target *-*-* } .-1 } + // { dg-error {mismatched types} "" { target *-*-* } .-2 } +} + +impl MemoryUnit for MemoryUnit { + extern "C" fn read_dword(&'s self) -> u16 { + let b16 = self.read_word() as u16; + + b16 << 8 + } +}