diff options
-rw-r--r-- | gcc/rust/ast/rust-ast-full-test.cc | 47 | ||||
-rw-r--r-- | gcc/rust/ast/rust-path.h | 172 | ||||
-rw-r--r-- | gcc/rust/expand/rust-attribute-visitor.cc | 21 | ||||
-rw-r--r-- | gcc/rust/hir/rust-ast-lower-base.cc | 41 | ||||
-rw-r--r-- | gcc/rust/hir/rust-ast-lower-type.h | 2 | ||||
-rw-r--r-- | gcc/rust/parse/rust-parse-impl.h | 83 | ||||
-rw-r--r-- | gcc/rust/parse/rust-parse.h | 2 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-type.cc | 47 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/const_generics_2.rs | 1 |
9 files changed, 253 insertions, 163 deletions
diff --git a/gcc/rust/ast/rust-ast-full-test.cc b/gcc/rust/ast/rust-ast-full-test.cc index d98a7cf..6c41d13 100644 --- a/gcc/rust/ast/rust-ast-full-test.cc +++ b/gcc/rust/ast/rust-ast-full-test.cc @@ -2598,28 +2598,14 @@ GenericArgs::as_string () const } // type args - if (!type_args.empty ()) + if (!generic_args.empty ()) { - auto i = type_args.begin (); - auto e = type_args.end (); + auto i = generic_args.begin (); + auto e = generic_args.end (); for (; i != e; i++) { - args += (*i)->as_string (); - if (e != i + 1) - args += ", "; - } - } - - // const args - if (!const_args.empty ()) - { - auto i = const_args.begin (); - auto e = const_args.end (); - - for (; i != e; i++) - { - args += i->as_string (); + args += (*i).as_string (); if (e != i + 1) args += ", "; } @@ -5800,15 +5786,28 @@ MetaWord::accept_vis (ASTVisitor &vis) vis.visit (*this); } -ConstGenericArg -ConstGenericArg::disambiguate_to_const () const +GenericArg +GenericArg::disambiguate_to_const () const { - rust_assert (get_kind () == Kind::Ambiguous); + rust_assert (get_kind () == Kind::Either); // FIXME: is it fine to have no outer attributes? - return ConstGenericArg (std::unique_ptr<Expr> ( - new IdentifierExpr (path, {}, locus)), - locus); + return GenericArg::create_const ( + std::unique_ptr<Expr> (new IdentifierExpr (path, {}, locus))); +} + +GenericArg +GenericArg::disambiguate_to_type () const +{ + rust_assert (get_kind () == Kind::Either); + + auto segment = std::unique_ptr<TypePathSegment> ( + new TypePathSegment (path, false, locus)); + auto segments = std::vector<std::unique_ptr<TypePathSegment>> (); + segments.emplace_back (std::move (segment)); + + return GenericArg::create_type ( + std::unique_ptr<Type> (new TypePath (std::move (segments), locus))); } } // namespace AST diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h index c6485c0..722ed93 100644 --- a/gcc/rust/ast/rust-path.h +++ b/gcc/rust/ast/rust-path.h @@ -132,7 +132,7 @@ public: }; /* Class representing a const generic application */ -class ConstGenericArg +class GenericArg { public: /** @@ -152,32 +152,43 @@ public: enum class Kind { Error, - Clear, - Ambiguous, + Const, // A const value + Type, // A type argument (not discernable during parsing) + Either, // Either a type or a const value, cleared up during resolving }; - static ConstGenericArg create_error () + static GenericArg create_error () { - return ConstGenericArg (nullptr, "", Kind::Error, Location ()); + return GenericArg (nullptr, nullptr, "", Kind::Error, Location ()); } - ConstGenericArg (std::unique_ptr<Expr> expression, Location locus) - : expression (std::move (expression)), path (""), kind (Kind::Clear), - locus (locus) - {} + static GenericArg create_const (std::unique_ptr<Expr> expression) + { + return GenericArg (std::move (expression), nullptr, "", Kind::Const, + expression->get_locus ()); + } - ConstGenericArg (Identifier path, Location locus) - : expression (nullptr), path (path), kind (Kind::Ambiguous), locus (locus) - {} + static GenericArg create_type (std::unique_ptr<Type> type) + { + return GenericArg (nullptr, std::move (type), "", Kind::Type, + type->get_locus ()); + } - ConstGenericArg (const ConstGenericArg &other) + static GenericArg create_ambiguous (Identifier path, Location locus) + { + return GenericArg (nullptr, nullptr, std::move (path), Kind::Either, locus); + } + + GenericArg (const GenericArg &other) : path (other.path), kind (other.kind), locus (other.locus) { if (other.expression) expression = other.expression->clone_expr (); + if (other.type) + type = other.type->clone_type (); } - ConstGenericArg operator= (const ConstGenericArg &other) + GenericArg operator= (const GenericArg &other) { kind = other.kind; path = other.path; @@ -185,6 +196,8 @@ public: if (other.expression) expression = other.expression->clone_expr (); + if (other.type) + type = other.type->clone_type (); return *this; } @@ -192,40 +205,63 @@ public: bool is_error () const { return kind == Kind::Error; } Kind get_kind () const { return kind; } + const Location &get_locus () const { return locus; } - const std::unique_ptr<AST::Expr> &get_expression () const + std::unique_ptr<Expr> &get_expression () { - rust_assert (kind == Kind::Clear); + rust_assert (kind == Kind::Const); return expression; } + std::unique_ptr<Type> &get_type () + { + rust_assert (kind == Kind::Type); + + return type; + } + + const std::string &get_path () const + { + rust_assert (kind == Kind::Either); + + return path; + } + std::string as_string () const { switch (get_kind ()) { case Kind::Error: gcc_unreachable (); - case Kind::Ambiguous: + case Kind::Either: return "Ambiguous: " + path; - case Kind::Clear: - return "Clear: { " + expression->as_string () + " }"; + case Kind::Const: + return "Const: { " + expression->as_string () + " }"; + case Kind::Type: + return "Type: " + type->as_string (); } return ""; } /** - * Disambiguate an amibguous const generic argument or generic type argument - * to a const generic argument, unequivocally + * Disambiguate an ambiguous generic argument to a const generic argument, + * unequivocally */ - ConstGenericArg disambiguate_to_const () const; + GenericArg disambiguate_to_const () const; + + /** + * Disambiguate an ambiguous generic argument to a type argument, + * unequivocally + */ + GenericArg disambiguate_to_type () const; private: - ConstGenericArg (std::unique_ptr<AST::Expr> expression, Identifier path, - Kind kind, Location locus) - : expression (std::move (expression)), path (std::move (path)), kind (kind), - locus (locus) + GenericArg (std::unique_ptr<Expr> expression, std::unique_ptr<Type> type, + Identifier path, Kind kind, Location locus) + : expression (std::move (expression)), type (std::move (type)), + path (std::move (path)), kind (kind), locus (locus) {} /** @@ -236,8 +272,14 @@ private: std::unique_ptr<Expr> expression; /** + * If the argument ends up being a type argument instead. A null pointer will + * be present here until the resolving phase. + */ + std::unique_ptr<Type> type; + + /** * Optional path which cannot be differentiated between a constant item and - * a type. Only used for `Ambiguous` const generic arguments, otherwise + * a type. Only used for ambiguous const generic arguments, otherwise * empty. */ Identifier path; @@ -262,14 +304,14 @@ class ConstGenericParam : public GenericParam /** * Default value for the const generic parameter */ - ConstGenericArg default_value; + GenericArg default_value; Attribute outer_attr; Location locus; public: ConstGenericParam (Identifier name, std::unique_ptr<AST::Type> type, - ConstGenericArg default_value, Attribute outer_attr, + GenericArg default_value, Attribute outer_attr, Location locus) : name (name), type (std::move (type)), default_value (std::move (default_value)), outer_attr (outer_attr), @@ -294,7 +336,14 @@ public: return type; } - const ConstGenericArg &get_default_value () const + GenericArg &get_default_value () + { + rust_assert (has_default_value ()); + + return default_value; + } + + const GenericArg &get_default_value () const { rust_assert (has_default_value ()); @@ -322,39 +371,32 @@ protected: struct GenericArgs { std::vector<Lifetime> lifetime_args; - std::vector<std::unique_ptr<Type> > type_args; + std::vector<GenericArg> generic_args; std::vector<GenericArgsBinding> binding_args; - std::vector<ConstGenericArg> const_args; Location locus; public: // Returns true if there are any generic arguments bool has_generic_args () const { - return !(lifetime_args.empty () && type_args.empty () - && binding_args.empty () && const_args.empty ()); + return !(lifetime_args.empty () && generic_args.empty () + && binding_args.empty ()); } GenericArgs (std::vector<Lifetime> lifetime_args, - std::vector<std::unique_ptr<Type> > type_args, + std::vector<GenericArg> generic_args, std::vector<GenericArgsBinding> binding_args, - std::vector<ConstGenericArg> const_args, Location locus = Location ()) : lifetime_args (std::move (lifetime_args)), - type_args (std::move (type_args)), - binding_args (std::move (binding_args)), - const_args (std::move (const_args)), locus (locus) + generic_args (std::move (generic_args)), + binding_args (std::move (binding_args)), locus (locus) {} // copy constructor with vector clone GenericArgs (GenericArgs const &other) - : lifetime_args (other.lifetime_args), binding_args (other.binding_args), - const_args (other.const_args), locus (other.locus) - { - type_args.reserve (other.type_args.size ()); - for (const auto &e : other.type_args) - type_args.push_back (e->clone_type ()); - } + : lifetime_args (other.lifetime_args), generic_args (other.generic_args), + binding_args (other.binding_args), locus (other.locus) + {} ~GenericArgs () = default; @@ -362,14 +404,10 @@ public: GenericArgs &operator= (GenericArgs const &other) { lifetime_args = other.lifetime_args; + generic_args = other.generic_args; binding_args = other.binding_args; - const_args = other.const_args; locus = other.locus; - type_args.reserve (other.type_args.size ()); - for (const auto &e : other.type_args) - type_args.push_back (e->clone_type ()); - return *this; } @@ -378,26 +416,18 @@ public: GenericArgs &operator= (GenericArgs &&other) = default; // Creates an empty GenericArgs (no arguments) - static GenericArgs create_empty () - { - return GenericArgs (std::vector<Lifetime> (), - std::vector<std::unique_ptr<Type> > (), - std::vector<GenericArgsBinding> (), - std::vector<ConstGenericArg> ()); - } + static GenericArgs create_empty () { return GenericArgs ({}, {}, {}); } std::string as_string () const; // TODO: is this better? Or is a "vis_pattern" better? - std::vector<std::unique_ptr<Type> > &get_type_args () { return type_args; } + std::vector<GenericArg> &get_generic_args () { return generic_args; } // TODO: is this better? Or is a "vis_pattern" better? std::vector<GenericArgsBinding> &get_binding_args () { return binding_args; } std::vector<Lifetime> &get_lifetime_args () { return lifetime_args; }; - std::vector<ConstGenericArg> &get_const_args () { return const_args; }; - Location get_locus () { return locus; } }; @@ -427,13 +457,12 @@ public: * args) */ PathExprSegment (std::string segment_name, Location locus, std::vector<Lifetime> lifetime_args = {}, - std::vector<std::unique_ptr<Type> > type_args = {}, - std::vector<GenericArgsBinding> binding_args = {}, - std::vector<ConstGenericArg> const_args = {}) + std::vector<GenericArg> generic_args = {}, + std::vector<GenericArgsBinding> binding_args = {}) : segment_name (PathIdentSegment (std::move (segment_name), locus)), - generic_args ( - GenericArgs (std::move (lifetime_args), std::move (type_args), - std::move (binding_args), std::move (const_args))), + generic_args (GenericArgs (std::move (lifetime_args), + std::move (generic_args), + std::move (binding_args))), locus (locus), node_id (Analysis::Mappings::get ()->get_next_node_id ()) {} @@ -724,15 +753,14 @@ public: TypePathSegmentGeneric (std::string segment_name, bool has_separating_scope_resolution, std::vector<Lifetime> lifetime_args, - std::vector<std::unique_ptr<Type> > type_args, + std::vector<GenericArg> generic_args, std::vector<GenericArgsBinding> binding_args, - std::vector<ConstGenericArg> const_args, Location locus) : TypePathSegment (std::move (segment_name), has_separating_scope_resolution, locus), - generic_args ( - GenericArgs (std::move (lifetime_args), std::move (type_args), - std::move (binding_args), std::move (const_args))) + generic_args (GenericArgs (std::move (lifetime_args), + std::move (generic_args), + std::move (binding_args))) {} std::string as_string () const override; diff --git a/gcc/rust/expand/rust-attribute-visitor.cc b/gcc/rust/expand/rust-attribute-visitor.cc index 90d91ee..bec6a9d 100644 --- a/gcc/rust/expand/rust-attribute-visitor.cc +++ b/gcc/rust/expand/rust-attribute-visitor.cc @@ -130,14 +130,23 @@ AttrVisitor::expand_generic_args (AST::GenericArgs &args) expander.push_context (MacroExpander::ContextType::TYPE); // expand type args - strip sub-types only - for (auto &type : args.get_type_args ()) + for (auto &arg : args.get_generic_args ()) { - type->accept_vis (*this); - maybe_expand_type (type); + // FIXME: Arthur: Another ugly hack while waiting for disambiguation + if (arg.get_kind () == AST::GenericArg::Kind::Either) + arg = arg.disambiguate_to_type (); - if (type->is_marked_for_strip ()) - rust_error_at (type->get_locus (), - "cannot strip type in this position"); + if (arg.get_kind () == AST::GenericArg::Kind::Type) + { + auto &type = arg.get_type (); + + type->accept_vis (*this); + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), + "cannot strip type in this position"); + } } expander.pop_context (); diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc index 7e80f81..6afbbe2 100644 --- a/gcc/rust/hir/rust-ast-lower-base.cc +++ b/gcc/rust/hir/rust-ast-lower-base.cc @@ -606,22 +606,37 @@ ASTLoweringBase::lower_generic_args (AST::GenericArgs &args) } std::vector<std::unique_ptr<HIR::Type>> type_args; - for (auto &type : args.get_type_args ()) + std::vector<HIR::ConstGenericArg> const_args; + + for (auto &arg : args.get_generic_args ()) { - HIR::Type *t = ASTLoweringType::translate (type.get ()); - type_args.push_back (std::unique_ptr<HIR::Type> (t)); + switch (arg.get_kind ()) + { + case AST::GenericArg::Kind::Type: { + auto type = ASTLoweringType::translate (arg.get_type ().get ()); + type_args.emplace_back (std::unique_ptr<HIR::Type> (type)); + break; + } + case AST::GenericArg::Kind::Const: { + auto expr + = ASTLoweringExpr::translate (arg.get_expression ().get ()); + const_args.emplace_back ( + HIR::ConstGenericArg (std::unique_ptr<HIR::Expr> (expr), + expr->get_locus ())); + break; + } + // FIXME: Arthur: Other horrible hack waiting for disambiguation + case AST::GenericArg::Kind::Either: { + arg = arg.disambiguate_to_type (); + auto type = ASTLoweringType::translate (arg.get_type ().get ()); + type_args.emplace_back (std::unique_ptr<HIR::Type> (type)); + break; + } + default: + gcc_unreachable (); + } } - std::vector<HIR::ConstGenericArg> const_args; - for (auto &const_arg : args.get_const_args ()) - const_args.emplace_back (HIR::ConstGenericArg ( - std::unique_ptr<HIR::Expr> ( - ASTLoweringExpr::translate (const_arg.get_expression ().get ())), - Location ())); - - // FIXME: - // const_arg.get_locus ()); - return HIR::GenericArgs (std::move (lifetime_args), std::move (type_args), std::move (binding_args), std::move (const_args), args.get_locus ()); diff --git a/gcc/rust/hir/rust-ast-lower-type.h b/gcc/rust/hir/rust-ast-lower-type.h index 2bcf0ee..a897c03 100644 --- a/gcc/rust/hir/rust-ast-lower-type.h +++ b/gcc/rust/hir/rust-ast-lower-type.h @@ -381,7 +381,7 @@ public: HIR::Expr *default_expr = nullptr; if (param.has_default_value () && param.get_default_value ().get_kind () - == AST::ConstGenericArg::Kind::Clear) + == AST::GenericArg::Kind::Const) default_expr = ASTLoweringExpr::translate ( param.get_default_value ().get_expression ().get ()); diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index 6a1a3a5..446df13 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -2878,12 +2878,12 @@ Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token) return nullptr; // optional default value - auto default_expr = AST::ConstGenericArg::create_error (); + auto default_expr = AST::GenericArg::create_error (); if (lexer.peek_token ()->get_id () == EQUAL) { lexer.skip_token (); auto tok = lexer.peek_token (); - default_expr = parse_const_generic_expression (); + default_expr = parse_generic_arg (); if (default_expr.is_error ()) rust_error_at (tok->get_locus (), @@ -2894,8 +2894,7 @@ Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token) // At this point, we *know* that we are parsing a const // expression - if (default_expr.get_kind () - == AST::ConstGenericArg::Kind::Ambiguous) + if (default_expr.get_kind () == AST::GenericArg::Kind::Either) default_expr = default_expr.disambiguate_to_const (); } @@ -6167,23 +6166,31 @@ Parser<ManagedTokenSource>::parse_type_path () } template <typename ManagedTokenSource> -AST::ConstGenericArg -Parser<ManagedTokenSource>::parse_const_generic_expression () +AST::GenericArg +Parser<ManagedTokenSource>::parse_generic_arg () { auto tok = lexer.peek_token (); std::unique_ptr<AST::Expr> expr = nullptr; switch (tok->get_id ()) { - case IDENTIFIER: - lexer.skip_token (); - - // TODO: This is ambiguous with regular generic types. We probably need - // to differentiate later on during type checking, and thus keep a - // special variant here - - // FIXME: We need locus here as well - return AST::ConstGenericArg (tok->get_str (), tok->get_locus ()); + case IDENTIFIER: { + // This is a bit of a weird situation: With an identifier token, we + // could either have a valid type or a macro (FIXME: anything else?). So + // we need one bit of lookahead to differentiate if this is really + auto next_tok = lexer.peek_token (1); + if (next_tok->get_id () == EXCLAM) + { + auto type = parse_type (); + if (type) + return AST::GenericArg::create_type (std::move (type)); + else + return AST::GenericArg::create_error (); + } + lexer.skip_token (); + return AST::GenericArg::create_ambiguous (tok->get_str (), + tok->get_locus ()); + } case LEFT_CURLY: expr = parse_block_expr (); break; @@ -6196,14 +6203,22 @@ Parser<ManagedTokenSource>::parse_const_generic_expression () case FALSE_LITERAL: expr = parse_literal_expr (); break; - default: - expr = nullptr; + // FIXME: Because of this, error reporting is garbage for const generic + // parameter's default values + default: { + auto type = parse_type (); + // FIXME: Find a better way to do this? + if (type) + return AST::GenericArg::create_type (std::move (type)); + else + return AST::GenericArg::create_error (); + } } if (!expr) - return AST::ConstGenericArg::create_error (); + return AST::GenericArg::create_error (); - return AST::ConstGenericArg (std::move (expr), tok->get_locus ()); + return AST::GenericArg::create_const (std::move (expr)); } // Parses the generic arguments in each path segment. @@ -6247,11 +6262,8 @@ Parser<ManagedTokenSource>::parse_path_generic_args () t = lexer.peek_token (); } - // try to parse types second - std::vector<std::unique_ptr<AST::Type>> type_args; - std::vector<AST::ConstGenericArg> const_args; - - // TODO: Keep list of const expressions as well + // try to parse types and const generics second + std::vector<AST::GenericArg> generic_args; // TODO: think of better control structure t = lexer.peek_token (); @@ -6265,20 +6277,14 @@ Parser<ManagedTokenSource>::parse_path_generic_args () && lexer.peek_token (1)->get_id () == EQUAL) break; - auto type = parse_type (false); - if (type) + auto arg = parse_generic_arg (); + if (!arg.is_error ()) { - type_args.emplace_back (std::move (type)); - } - else - { - auto const_generic_expr = parse_const_generic_expression (); - if (const_generic_expr.is_error ()) - break; - else - const_args.emplace_back (std::move (const_generic_expr)); + generic_args.emplace_back (std::move (arg)); } + // FIXME: Do we need to break if we encounter an error? + // if next token isn't comma, then it must be end of list if (lexer.peek_token ()->get_id () != COMMA) break; @@ -6323,12 +6329,11 @@ Parser<ManagedTokenSource>::parse_path_generic_args () return AST::GenericArgs::create_empty (); lifetime_args.shrink_to_fit (); - type_args.shrink_to_fit (); + generic_args.shrink_to_fit (); binding_args.shrink_to_fit (); - return AST::GenericArgs (std::move (lifetime_args), std::move (type_args), - std::move (binding_args), std::move (const_args), - locus); + return AST::GenericArgs (std::move (lifetime_args), std::move (generic_args), + std::move (binding_args), locus); } // Parses a binding in a generic args path segment. diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index fa88f8e..23a1e7c 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -177,7 +177,7 @@ private: AST::TypePath parse_type_path (); std::unique_ptr<AST::TypePathSegment> parse_type_path_segment (); AST::PathIdentSegment parse_path_ident_segment (); - AST::ConstGenericArg parse_const_generic_expression (); + AST::GenericArg parse_generic_arg (); AST::GenericArgs parse_path_generic_args (); AST::GenericArgsBinding parse_generic_args_binding (); AST::TypePathFunction parse_type_path_function (Location locus); diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc index 910468e..e875688 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.cc +++ b/gcc/rust/resolve/rust-ast-resolve-type.cc @@ -384,12 +384,35 @@ ResolveTypeToCanonicalPath::visit (AST::TypePath &path) std::vector<CanonicalPath> args; if (s->has_generic_args ()) { - for (auto > : s->get_generic_args ().get_type_args ()) + for (auto &generic : s->get_generic_args ().get_generic_args ()) { - CanonicalPath arg = CanonicalPath::create_empty (); - bool ok = ResolveTypeToCanonicalPath::go (gt.get (), arg); - if (ok) - args.push_back (std::move (arg)); + // FIXME: What do we want to do here in case there is a + // constant or an ambiguous const generic? + // TODO: At that point, will all generics have been + // disambiguated? Can we thus canonical resolve types and + // const and `gcc_unreachable` on ambiguous types? + // + // FIXME: Arthur: This is an ugly hack to resolve just as + // much as before despite not handling ambiguity yet. The + // calls to `clone_type` will be removed. + std::unique_ptr<AST::Type> gt = nullptr; + + if (generic.get_kind () == AST::GenericArg::Kind::Type) + gt = generic.get_type ()->clone_type (); + else if (generic.get_kind () + == AST::GenericArg::Kind::Either) + gt = generic.disambiguate_to_type () + .get_type () + ->clone_type (); + + if (gt) + { + CanonicalPath arg = CanonicalPath::create_empty (); + bool ok + = ResolveTypeToCanonicalPath::go (gt.get (), arg); + if (ok) + args.push_back (std::move (arg)); + } } } @@ -472,8 +495,18 @@ ResolveTypeToCanonicalPath::ResolveTypeToCanonicalPath () void ResolveGenericArgs::go (AST::GenericArgs &args) { - for (auto > : args.get_type_args ()) - ResolveType::go (gt.get ()); + for (auto &arg : args.get_generic_args ()) + { + // FIXME: Arthur: Ugly hack while waiting for disambiguation + if (arg.get_kind () == AST::GenericArg::Kind::Either) + arg = arg.disambiguate_to_type (); + + if (arg.get_kind () == AST::GenericArg::Kind::Type) + ResolveType::go (arg.get_type ().get ()); + + // else... + // We need to use a switch instead + } } } // namespace Resolver diff --git a/gcc/testsuite/rust/compile/const_generics_2.rs b/gcc/testsuite/rust/compile/const_generics_2.rs index 82d2676..98495cf 100644 --- a/gcc/testsuite/rust/compile/const_generics_2.rs +++ b/gcc/testsuite/rust/compile/const_generics_2.rs @@ -1,3 +1,4 @@ struct Foo<const N>; // { dg-error "expecting .:. but .>. found" } struct Bar<const N: >; // { dg-error "unrecognised token .>. in type" } struct Baz<const N: usize = >; // { dg-error "invalid token for start of default value for const generic parameter" } +// { dg-error "unrecognised token .>. in type" "" { target *-*-* } .-1 } |