libcpp, c, middle-end: Optimize initializers using #embed in C
[official-gcc.git] / gcc / rust / backend / rust-compile-resolve-path.cc
blob3bb45a537508d6b947ec571ab8b04531753a1b0e
1 // Copyright (C) 2020-2024 Free Software Foundation, Inc.
3 // This file is part of GCC.
5 // GCC is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU General Public License as published by the Free
7 // Software Foundation; either version 3, or (at your option) any later
8 // version.
10 // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 // for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with GCC; see the file COPYING3. If not see
17 // <http://www.gnu.org/licenses/>.
19 #include "rust-compile-resolve-path.h"
20 #include "options.h"
21 #include "rust-compile-intrinsic.h"
22 #include "rust-compile-item.h"
23 #include "rust-compile-implitem.h"
24 #include "rust-compile-expr.h"
25 #include "rust-hir-map.h"
26 #include "rust-hir-trait-resolve.h"
27 #include "rust-hir-path-probe.h"
28 #include "rust-compile-extern.h"
29 #include "rust-constexpr.h"
30 #include "rust-tyty.h"
32 namespace Rust {
33 namespace Compile {
35 void
36 ResolvePathRef::visit (HIR::QualifiedPathInExpression &expr)
38 resolved = resolve (expr.get_final_segment ().get_segment (),
39 expr.get_mappings (), expr.get_locus (), true);
42 void
43 ResolvePathRef::visit (HIR::PathInExpression &expr)
45 resolved = resolve (expr.get_final_segment ().get_segment (),
46 expr.get_mappings (), expr.get_locus (), false);
49 tree
50 ResolvePathRef::attempt_constructor_expression_lookup (
51 TyTy::BaseType *lookup, Context *ctx, const Analysis::NodeMapping &mappings,
52 location_t expr_locus)
54 // it might be an enum data-less enum variant
55 if (lookup->get_kind () != TyTy::TypeKind::ADT)
56 return error_mark_node;
58 TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
59 if (adt->is_unit ())
60 return unit_expression (ctx, expr_locus);
62 if (!adt->is_enum ())
63 return error_mark_node;
65 HirId variant_id;
66 if (!ctx->get_tyctx ()->lookup_variant_definition (mappings.get_hirid (),
67 &variant_id))
68 return error_mark_node;
70 int union_disriminator = -1;
71 TyTy::VariantDef *variant = nullptr;
72 if (!adt->lookup_variant_by_id (variant_id, &variant, &union_disriminator))
73 return error_mark_node;
75 // this can only be for discriminant variants the others are built up
76 // using call-expr or struct-init
77 rust_assert (variant->get_variant_type ()
78 == TyTy::VariantDef::VariantType::NUM);
80 // we need the actual gcc type
81 tree compiled_adt_type = TyTyResolveCompile::compile (ctx, adt);
83 // make the ctor for the union
84 HIR::Expr *discrim_expr = variant->get_discriminant ();
85 tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
86 tree folded_discrim_expr = fold_expr (discrim_expr_node);
87 tree qualifier = folded_discrim_expr;
89 return Backend::constructor_expression (compiled_adt_type, true, {qualifier},
90 union_disriminator, expr_locus);
93 tree
94 ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
95 const Analysis::NodeMapping &mappings,
96 location_t expr_locus, bool is_qualified_path)
98 TyTy::BaseType *lookup = nullptr;
99 bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup);
100 rust_assert (ok);
102 // need to look up the reference for this identifier
104 // this can fail because it might be a Constructor for something
105 // in that case the caller should attempt ResolvePathType::Compile
106 NodeId ref_node_id = UNKNOWN_NODEID;
107 if (flag_name_resolution_2_0)
109 auto nr_ctx
110 = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
112 auto resolved = nr_ctx.lookup (mappings.get_nodeid ());
114 if (!resolved)
115 return attempt_constructor_expression_lookup (lookup, ctx, mappings,
116 expr_locus);
118 ref_node_id = *resolved;
120 else
122 if (!ctx->get_resolver ()->lookup_resolved_name (mappings.get_nodeid (),
123 &ref_node_id))
124 return attempt_constructor_expression_lookup (lookup, ctx, mappings,
125 expr_locus);
128 HirId ref;
129 if (!ctx->get_mappings ()->lookup_node_to_hir (ref_node_id, &ref))
131 rust_error_at (expr_locus, "reverse call path lookup failure");
132 return error_mark_node;
135 // might be a constant
136 tree constant_expr;
137 if (ctx->lookup_const_decl (ref, &constant_expr))
139 TREE_USED (constant_expr) = 1;
140 return constant_expr;
143 // maybe closure binding
144 tree closure_binding = error_mark_node;
145 if (ctx->lookup_closure_binding (ref, &closure_binding))
147 TREE_USED (closure_binding) = 1;
148 return closure_binding;
151 // this might be a variable reference or a function reference
152 Bvariable *var = nullptr;
153 if (ctx->lookup_var_decl (ref, &var))
155 // TREE_USED is setup in the gcc abstraction here
156 return Backend::var_expression (var, expr_locus);
159 // might be a match pattern binding
160 tree binding = error_mark_node;
161 if (ctx->lookup_pattern_binding (ref, &binding))
163 TREE_USED (binding) = 1;
164 return binding;
167 // it might be a function call
168 if (lookup->get_kind () == TyTy::TypeKind::FNDEF)
170 TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
171 tree fn = NULL_TREE;
172 if (ctx->lookup_function_decl (fntype->get_ty_ref (), &fn))
174 TREE_USED (fn) = 1;
175 return address_expression (fn, expr_locus);
177 else if (fntype->get_abi () == ABI::INTRINSIC)
179 Intrinsics compile (ctx);
180 fn = compile.compile (fntype);
181 TREE_USED (fn) = 1;
182 return address_expression (fn, expr_locus);
186 // let the query system figure it out
187 tree resolved_item = query_compile (ref, lookup, final_segment, mappings,
188 expr_locus, is_qualified_path);
189 if (resolved_item != error_mark_node)
191 TREE_USED (resolved_item) = 1;
193 return resolved_item;
196 tree
197 HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup,
198 const HIR::PathIdentSegment &final_segment,
199 const Analysis::NodeMapping &mappings,
200 location_t expr_locus, bool is_qualified_path)
202 HIR::Item *resolved_item = ctx->get_mappings ()->lookup_hir_item (ref);
203 HirId parent_block;
204 HIR::ExternalItem *resolved_extern_item
205 = ctx->get_mappings ()->lookup_hir_extern_item (ref, &parent_block);
206 bool is_hir_item = resolved_item != nullptr;
207 bool is_hir_extern_item = resolved_extern_item != nullptr;
208 bool is_fn = lookup->get_kind () == TyTy::TypeKind::FNDEF;
209 if (is_hir_item)
211 if (!lookup->has_substitutions_defined ())
212 return CompileItem::compile (resolved_item, ctx, nullptr, true,
213 expr_locus);
214 else
215 return CompileItem::compile (resolved_item, ctx, lookup, true,
216 expr_locus);
218 else if (is_hir_extern_item)
220 if (!lookup->has_substitutions_defined ())
221 return CompileExternItem::compile (resolved_extern_item, ctx, nullptr,
222 true, expr_locus);
223 else
224 return CompileExternItem::compile (resolved_extern_item, ctx, lookup,
225 true, expr_locus);
227 else
229 if (is_fn)
231 TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
232 TyTy::BaseType *receiver = nullptr;
234 if (fn->is_method ())
236 receiver = fn->get_self_type ();
237 receiver = receiver->destructure ();
239 return resolve_method_address (fn, receiver, expr_locus);
243 HirId parent_impl_id = UNKNOWN_HIRID;
244 HIR::ImplItem *resolved_item
245 = ctx->get_mappings ()->lookup_hir_implitem (ref, &parent_impl_id);
246 bool is_impl_item = resolved_item != nullptr;
247 if (is_impl_item)
249 if (!lookup->has_substitutions_defined ())
250 return CompileInherentImplItem::Compile (resolved_item, ctx,
251 nullptr, true, expr_locus);
252 else
253 return CompileInherentImplItem::Compile (resolved_item, ctx, lookup,
254 true, expr_locus);
256 else
258 // it might be resolved to a trait item
259 HIR::TraitItem *trait_item
260 = ctx->get_mappings ()->lookup_hir_trait_item (ref);
261 HIR::Trait *trait = ctx->get_mappings ()->lookup_trait_item_mapping (
262 trait_item->get_mappings ().get_hirid ());
264 Resolver::TraitReference *trait_ref
265 = &Resolver::TraitReference::error_node ();
266 bool ok = ctx->get_tyctx ()->lookup_trait_reference (
267 trait->get_mappings ().get_defid (), &trait_ref);
268 rust_assert (ok);
270 TyTy::BaseType *receiver = nullptr;
271 ok = ctx->get_tyctx ()->lookup_receiver (mappings.get_hirid (),
272 &receiver);
273 rust_assert (ok);
274 receiver = receiver->destructure ();
276 // the type resolver can only resolve type bounds to their trait
277 // item so its up to us to figure out if this path should resolve
278 // to an trait-impl-block-item or if it can be defaulted to the
279 // trait-impl-item's definition
280 auto candidates
281 = Resolver::PathProbeImplTrait::Probe (receiver, final_segment,
282 trait_ref);
283 if (candidates.size () == 0)
285 // this means we are defaulting back to the trait_item if
286 // possible
287 Resolver::TraitItemReference *trait_item_ref = nullptr;
288 bool ok = trait_ref->lookup_hir_trait_item (*trait_item,
289 &trait_item_ref);
290 rust_assert (ok); // found
291 rust_assert (trait_item_ref->is_optional ()); // has definition
293 return CompileTraitItem::Compile (
294 trait_item_ref->get_hir_trait_item (), ctx, lookup, true,
295 expr_locus);
297 else
299 rust_assert (candidates.size () == 1);
301 auto candidate = *candidates.begin ();
302 rust_assert (candidate.is_impl_candidate ());
304 HIR::ImplBlock *impl = candidate.item.impl.parent;
305 HIR::ImplItem *impl_item = candidate.item.impl.impl_item;
307 TyTy::BaseType *self = nullptr;
308 bool ok = ctx->get_tyctx ()->lookup_type (
309 impl->get_type ()->get_mappings ().get_hirid (), &self);
310 rust_assert (ok);
312 if (!lookup->has_substitutions_defined ())
313 return CompileInherentImplItem::Compile (impl_item, ctx,
314 nullptr, true,
315 expr_locus);
316 else
317 return CompileInherentImplItem::Compile (impl_item, ctx, lookup,
318 true, expr_locus);
323 return error_mark_node;
326 } // namespace Compile
327 } // namespace Rust