mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 19:00:11 +01:00
Reimplement derived class thunk in terms of down-casting (#7322)
This helps us move away from the clone-with-modifications approach to thunking, which gets unwieldy as signatures get more complex. --------- Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
co-authored by
Richard Smith
parent
1a26b57732
commit
85c53fa00c
@@ -263,13 +263,12 @@ auto PerformCallToFunction(Context& context, SemIR::LocId loc_id,
|
||||
switch (callee.special_function_kind) {
|
||||
case SemIR::Function::SpecialFunctionKind::Thunk: {
|
||||
// If we're about to form a direct call to a thunk, inline it.
|
||||
auto callee_inst_id =
|
||||
context.sem_ir().thunks().Get(callee.thunk_id()).callee_id;
|
||||
LoadImportRef(context, callee_inst_id);
|
||||
const auto& thunk_info = context.sem_ir().thunks().Get(callee.thunk_id());
|
||||
LoadImportRef(context, thunk_info.callee_id);
|
||||
|
||||
// Name the thunk target within the enclosing scope of the thunk.
|
||||
auto thunk_ref_id =
|
||||
BuildNameRef(context, loc_id, callee.name_id, callee_inst_id,
|
||||
BuildNameRef(context, loc_id, callee.name_id, thunk_info.callee_id,
|
||||
callee_function.enclosing_specific_id);
|
||||
|
||||
auto param_pattern_ids =
|
||||
@@ -279,9 +278,10 @@ auto PerformCallToFunction(Context& context, SemIR::LocId loc_id,
|
||||
|
||||
// This recurses back into `PerformCall`. However, we never form a thunk
|
||||
// to a thunk, so we only recurse once.
|
||||
return PerformThunkCall(
|
||||
context, loc_id, callee_function.function_id, param_pattern_ids,
|
||||
context.inst_blocks().Get(converted_args_id), thunk_ref_id);
|
||||
return PerformThunkCall(context, loc_id, callee_function.function_id,
|
||||
param_pattern_ids,
|
||||
context.inst_blocks().Get(converted_args_id),
|
||||
thunk_ref_id, thunk_info.override_self_type_id);
|
||||
}
|
||||
|
||||
case SemIR::Function::SpecialFunctionKind::HasCppThunk: {
|
||||
|
||||
@@ -929,10 +929,19 @@ static auto ConvertStructToClass(Context& context, SemIR::StructType src_type,
|
||||
is_partial ? nullptr : &dest_type);
|
||||
}
|
||||
|
||||
// An inheritance path is a sequence of `BaseDecl`s and corresponding base types
|
||||
// in order from derived to base.
|
||||
using InheritancePath =
|
||||
llvm::SmallVector<std::pair<SemIR::InstId, SemIR::TypeId>>;
|
||||
// Represents an edge in the inheritance graph, created by a `base` declaration.
|
||||
struct InheritanceEdge {
|
||||
// The class type of the class containing the `base` declaration.
|
||||
SemIR::TypeId derived_type_id;
|
||||
// The `base` declaration itself.
|
||||
SemIR::InstId base_decl_id;
|
||||
// The type of the `base` declaration.
|
||||
SemIR::TypeId base_type_id;
|
||||
};
|
||||
|
||||
// An inheritance path is a sequence of `InheritanceEdge`s, in order from
|
||||
// derived to base.
|
||||
using InheritancePath = llvm::SmallVector<InheritanceEdge>;
|
||||
|
||||
// Computes the inheritance path from class `derived_id` to class `base_id`.
|
||||
// Returns nullopt if `derived_id` is not a class derived from `base_id`.
|
||||
@@ -964,7 +973,9 @@ static auto ComputeInheritancePath(Context& context, SemIR::LocId loc_id,
|
||||
result = std::nullopt;
|
||||
break;
|
||||
}
|
||||
result->push_back({derived_class.base_id, base_type_id});
|
||||
result->push_back({.derived_type_id = derived_id,
|
||||
.base_decl_id = derived_class.base_id,
|
||||
.base_type_id = base_type_id});
|
||||
derived_id = base_type_id;
|
||||
}
|
||||
return result;
|
||||
@@ -985,7 +996,7 @@ static auto ConvertDerivedToBase(Context& context, SemIR::LocId loc_id,
|
||||
.second;
|
||||
|
||||
// Add a series of `.base` accesses.
|
||||
for (auto [base_id, base_type_id] : path) {
|
||||
for (auto [_, base_id, base_type_id] : path) {
|
||||
auto base_decl = context.insts().GetAs<SemIR::BaseDecl>(base_id);
|
||||
value_id = AddInst<SemIR::ClassElementAccess>(
|
||||
context, loc_id,
|
||||
@@ -2360,6 +2371,66 @@ auto DiscardExpr(Context& context, SemIR::InstId expr_id) -> void {
|
||||
// TODO: This will eventually need to do some "do not discard" analysis.
|
||||
}
|
||||
|
||||
auto UnsafeUndoConvert(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::InstId expr_id, SemIR::TypeId type_id)
|
||||
-> SemIR::InstId {
|
||||
auto source_type_id = context.insts().Get(expr_id).type_id();
|
||||
// Preserve type qualifiers.
|
||||
auto quals =
|
||||
context.types().GetUnqualifiedTypeAndQualifiers(source_type_id).second;
|
||||
auto path = ComputeInheritancePath(context, loc_id, type_id, source_type_id);
|
||||
CARBON_CHECK(path.has_value(),
|
||||
"only derived-to-base conversions can currently be undone");
|
||||
|
||||
if (path->empty()) {
|
||||
// No-op conversion.
|
||||
return expr_id;
|
||||
}
|
||||
|
||||
auto source_category = SemIR::GetExprCategory(context.sem_ir(), expr_id);
|
||||
switch (source_category) {
|
||||
case SemIR::ExprCategory::NotExpr:
|
||||
case SemIR::ExprCategory::Error:
|
||||
case SemIR::ExprCategory::Pattern:
|
||||
case SemIR::ExprCategory::ReprInitializing:
|
||||
case SemIR::ExprCategory::InPlaceInitializing:
|
||||
case SemIR::ExprCategory::Mixed:
|
||||
case SemIR::ExprCategory::Dependent:
|
||||
case SemIR::ExprCategory::RefTagged:
|
||||
CARBON_FATAL("Unsupported category {0} for base-to-derived conversion",
|
||||
source_category);
|
||||
case SemIR::ExprCategory::EphemeralRef:
|
||||
case SemIR::ExprCategory::DurableRef:
|
||||
break;
|
||||
case SemIR::ExprCategory::Value:
|
||||
if (auto ref_expr_id = TryMakeValueAsRef(context, expr_id);
|
||||
ref_expr_id.has_value()) {
|
||||
expr_id = ref_expr_id;
|
||||
} else {
|
||||
CARBON_FATAL("Types must have pointer value-representation");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
auto result_id = expr_id;
|
||||
for (auto edge : llvm::reverse(*path)) {
|
||||
auto base_decl = context.insts().GetAs<SemIR::BaseDecl>(edge.base_decl_id);
|
||||
result_id = AddInst<SemIR::EnclosingClassAccess>(
|
||||
context, loc_id,
|
||||
{.type_id = GetQualifiedType(context, edge.derived_type_id, quals),
|
||||
.element_id = result_id,
|
||||
.index = base_decl.index});
|
||||
}
|
||||
|
||||
if (source_category == SemIR::ExprCategory::Value) {
|
||||
result_id = AddInst<SemIR::AcquireValue>(
|
||||
context, loc_id,
|
||||
{.type_id = GetQualifiedType(context, type_id, quals),
|
||||
.value_id = result_id});
|
||||
}
|
||||
return result_id;
|
||||
}
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
// NOLINTEND(misc-no-recursion)
|
||||
|
||||
@@ -265,6 +265,13 @@ auto ReturnExprAsForm(Context& context, SemIR::LocId loc_id,
|
||||
// Handles an expression whose result value is unused.
|
||||
auto DiscardExpr(Context& context, SemIR::InstId expr_id) -> void;
|
||||
|
||||
// Given that `expr_id` is the result of a conversion from an expression of
|
||||
// type `type_id`, this undoes that conversion. Currently, this only supports
|
||||
// the case where the original conversion was a derived-to-base conversion.
|
||||
auto UnsafeUndoConvert(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::InstId expr_id, SemIR::TypeId type_id)
|
||||
-> SemIR::InstId;
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_CHECK_CONVERT_H_
|
||||
|
||||
@@ -697,10 +697,26 @@ auto CarbonExternalASTSource::CompleteType(clang::TagDecl* tag_decl) -> void {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto callee_function =
|
||||
GetCalleeAsFunction(context_->sem_ir(), vtable_entry_id);
|
||||
const SemIR::Function& function =
|
||||
context_->functions().Get(callee_function.function_id);
|
||||
// The Carbon vtable entry for a function override is a thunk, which wraps
|
||||
// the function declaration to expose the signature of the overridden
|
||||
// virtual function. Here we want to generate a C++ method declaration for
|
||||
// the override, so we need to look through the thunk wrapping.
|
||||
const auto [callee_function, function] =
|
||||
[&]() -> std::pair<SemIR::CalleeFunction, const SemIR::Function&> {
|
||||
auto vtable_callee_function =
|
||||
GetCalleeAsFunction(context_->sem_ir(), vtable_entry_id);
|
||||
const SemIR::Function& vtable_function =
|
||||
context_->functions().Get(vtable_callee_function.function_id);
|
||||
if (!vtable_function.thunk_id().has_value()) {
|
||||
return {vtable_callee_function, vtable_function};
|
||||
}
|
||||
auto vtable_thunk =
|
||||
context_->sem_ir().thunks().Get(vtable_function.thunk_id());
|
||||
auto callee_function =
|
||||
GetCalleeAsFunction(context_->sem_ir(), vtable_thunk.callee_id);
|
||||
return {callee_function,
|
||||
context_->functions().Get(callee_function.function_id)};
|
||||
}();
|
||||
|
||||
// If this is a member of a base class, nothing to do here.
|
||||
if (function.parent_scope_id != class_info.scope_id) {
|
||||
|
||||
@@ -51,6 +51,7 @@ class DeferredDefinitionWorklist {
|
||||
SemIR::FunctionId function_id;
|
||||
SemIR::InstId decl_id;
|
||||
SemIR::InstId callee_id;
|
||||
SemIR::TypeId override_self_type_id;
|
||||
};
|
||||
|
||||
// A worklist task that indicates we should define a thunk that was previously
|
||||
|
||||
@@ -304,12 +304,10 @@ auto CheckFunctionTypeMatches(Context& context,
|
||||
const SemIR::Function& new_function,
|
||||
const SemIR::Function& prev_function,
|
||||
SemIR::SpecificId prev_specific_id,
|
||||
bool check_syntax,
|
||||
SemIR::TypeId self_type_override_id,
|
||||
bool diagnose) -> bool {
|
||||
bool check_syntax, bool diagnose) -> bool {
|
||||
if (!CheckRedeclParamsMatch(context, DeclParams(new_function),
|
||||
DeclParams(prev_function), prev_specific_id,
|
||||
diagnose, check_syntax, self_type_override_id)) {
|
||||
diagnose, check_syntax)) {
|
||||
return false;
|
||||
}
|
||||
if (!CheckFunctionReturnTypeMatches(context, new_function, prev_function,
|
||||
|
||||
@@ -71,16 +71,11 @@ auto CheckFunctionReturnTypeMatches(Context& context,
|
||||
//
|
||||
// `check_syntax` is false if the redeclaration can be called via a thunk with
|
||||
// implicit conversions from the original declaration.
|
||||
//
|
||||
// If `self_type_override_id` is specified, the self type is checked against
|
||||
// that type instead of the type from `prev_function`. This is used to check
|
||||
// virtual function overrides.
|
||||
auto CheckFunctionTypeMatches(
|
||||
Context& context, const SemIR::Function& new_function,
|
||||
const SemIR::Function& prev_function, SemIR::SpecificId prev_specific_id,
|
||||
bool check_syntax,
|
||||
SemIR::TypeId self_type_override_id = SemIR::TypeId::None,
|
||||
bool diagnose = true) -> bool;
|
||||
auto CheckFunctionTypeMatches(Context& context,
|
||||
const SemIR::Function& new_function,
|
||||
const SemIR::Function& prev_function,
|
||||
SemIR::SpecificId prev_specific_id,
|
||||
bool check_syntax, bool diagnose = true) -> bool;
|
||||
|
||||
inline auto CheckFunctionTypeMatches(Context& context,
|
||||
const SemIR::Function& new_function,
|
||||
|
||||
@@ -206,8 +206,7 @@ static auto CheckRedeclParam(Context& context, bool is_implicit_param,
|
||||
SemIR::InstId orig_new_param_pattern_id,
|
||||
SemIR::InstId orig_prev_param_pattern_id,
|
||||
SemIR::SpecificId prev_specific_id, bool diagnose,
|
||||
bool check_syntax,
|
||||
SemIR::TypeId self_type_override_id) -> bool {
|
||||
bool check_syntax) -> bool {
|
||||
CARBON_DIAGNOSTIC(
|
||||
RedeclParamPrevious, Note,
|
||||
"previous declaration's corresponding {0:implicit |}parameter here",
|
||||
@@ -304,15 +303,6 @@ static auto CheckRedeclParam(Context& context, bool is_implicit_param,
|
||||
.Get(prev_any_binding_pattern.entity_name_id)
|
||||
.name_id;
|
||||
|
||||
// If this is the self parameter, and we have a type override for it,
|
||||
// check against that type instead.
|
||||
if (new_name_id == SemIR::NameId::SelfValue &&
|
||||
prev_name_id == SemIR::NameId::SelfValue &&
|
||||
self_type_override_id.has_value()) {
|
||||
check_type = false;
|
||||
check_for_type_mismatch_with(self_type_override_id);
|
||||
}
|
||||
|
||||
if (new_any_binding_pattern.kind ==
|
||||
SemIR::WrapperBindingPattern::Kind) {
|
||||
// The subpattern handling will take care of checking for type
|
||||
@@ -347,8 +337,7 @@ static auto CheckRedeclParams(Context& context, SemIR::LocId new_decl_loc_id,
|
||||
SemIR::InstBlockId prev_param_patterns_id,
|
||||
bool is_implicit_param,
|
||||
SemIR::SpecificId prev_specific_id, bool diagnose,
|
||||
bool check_syntax,
|
||||
SemIR::TypeId self_type_override_id) -> bool {
|
||||
bool check_syntax) -> bool {
|
||||
// This will often occur for empty params.
|
||||
if (new_param_patterns_id == prev_param_patterns_id) {
|
||||
return true;
|
||||
@@ -406,8 +395,7 @@ static auto CheckRedeclParams(Context& context, SemIR::LocId new_decl_loc_id,
|
||||
llvm::enumerate(new_param_pattern_ids, prev_param_pattern_ids)) {
|
||||
if (!CheckRedeclParam(context, is_implicit_param, index,
|
||||
new_param_pattern_id, prev_param_pattern_id,
|
||||
prev_specific_id, diagnose, check_syntax,
|
||||
self_type_override_id)) {
|
||||
prev_specific_id, diagnose, check_syntax)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -530,8 +518,7 @@ static auto CheckRedeclParamSyntax(Context& context,
|
||||
auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity,
|
||||
const DeclParams& prev_entity,
|
||||
SemIR::SpecificId prev_specific_id, bool diagnose,
|
||||
bool check_syntax,
|
||||
SemIR::TypeId self_type_override_id) -> bool {
|
||||
bool check_syntax) -> bool {
|
||||
if (EntityHasParamError(context, new_entity) ||
|
||||
EntityHasParamError(context, prev_entity)) {
|
||||
return false;
|
||||
@@ -539,17 +526,15 @@ auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity,
|
||||
if (!CheckRedeclParams(
|
||||
context, new_entity.loc_id, new_entity.implicit_param_patterns_id,
|
||||
prev_entity.loc_id, prev_entity.implicit_param_patterns_id,
|
||||
/*is_implicit_param=*/true, prev_specific_id, diagnose, check_syntax,
|
||||
self_type_override_id)) {
|
||||
/*is_implicit_param=*/true, prev_specific_id, diagnose,
|
||||
check_syntax)) {
|
||||
return false;
|
||||
}
|
||||
// Don't forward `self_type_override_id` here because it's extra cost, and
|
||||
// `self` is only allowed in implicit params.
|
||||
if (!CheckRedeclParams(context, new_entity.loc_id,
|
||||
new_entity.param_patterns_id, prev_entity.loc_id,
|
||||
prev_entity.param_patterns_id,
|
||||
/*is_implicit_param=*/false, prev_specific_id,
|
||||
diagnose, check_syntax, SemIR::TypeId::None)) {
|
||||
diagnose, check_syntax)) {
|
||||
return false;
|
||||
}
|
||||
if (check_syntax &&
|
||||
|
||||
@@ -95,14 +95,11 @@ struct DeclParams {
|
||||
|
||||
// Checks that the parameters in a redeclaration of an entity match the
|
||||
// parameters in the prior declaration. If not, produces a diagnostic if
|
||||
// `diagnose` is true, and returns false. If `self_type_override_id` is
|
||||
// specified, the type of `self` will be compared against that type instead of
|
||||
// the `self` type from `prev_entity`.
|
||||
auto CheckRedeclParamsMatch(
|
||||
Context& context, const DeclParams& new_entity,
|
||||
const DeclParams& prev_entity, SemIR::SpecificId prev_specific_id,
|
||||
bool diagnose, bool check_syntax,
|
||||
SemIR::TypeId self_type_override_id = SemIR::TypeId::None) -> bool;
|
||||
// `diagnose` is true, and returns false.
|
||||
auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity,
|
||||
const DeclParams& prev_entity,
|
||||
SemIR::SpecificId prev_specific_id, bool diagnose,
|
||||
bool check_syntax) -> bool;
|
||||
|
||||
inline auto CheckRedeclParamsMatch(Context& context,
|
||||
const DeclParams& new_entity,
|
||||
|
||||
+201
-60
@@ -309,18 +309,18 @@ class T2 {
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
base class T1 {
|
||||
// CHECK:STDERR: fail_ref_self_mismatch.carbon:[[@LINE+3]]:17: error: value expression passed to reference parameter [ValueForRefParam]
|
||||
// CHECK:STDERR: virtual fn F1[self: Self]();
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
virtual fn F1[self: Self]();
|
||||
}
|
||||
|
||||
class T2 {
|
||||
extend base: T1;
|
||||
// CHECK:STDERR: fail_ref_self_mismatch.carbon:[[@LINE+10]]:3: error: value expression passed to reference parameter [ValueForRefParam]
|
||||
// CHECK:STDERR: override fn F1[ref self: Self]();
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_ref_self_mismatch.carbon:[[@LINE+7]]:18: note: initializing function parameter [InCallToFunctionParam]
|
||||
// CHECK:STDERR: override fn F1[ref self: Self]();
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_ref_self_mismatch.carbon:[[@LINE-8]]:3: note: while building thunk to match the signature of this function [ThunkSignature]
|
||||
// CHECK:STDERR: fail_ref_self_mismatch.carbon:[[@LINE-11]]:3: note: while building thunk to match the signature of this function [ThunkSignature]
|
||||
// CHECK:STDERR: virtual fn F1[self: Self]();
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
@@ -648,11 +648,13 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.<vptr>: %ptr.454} [concrete]
|
||||
// CHECK:STDOUT: %Derived.elem: type = unbound_element_type %Derived, %Base [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.746: type = pattern_type %Derived [concrete]
|
||||
// CHECK:STDOUT: %Derived.H.type: type = fn_type @Derived.H [concrete]
|
||||
// CHECK:STDOUT: %Derived.H.type.1f42d4.1: type = fn_type @Derived.H.loc9_30.1 [concrete]
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %Derived.H: %Derived.H.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %Derived.H.a6796b.1: %Derived.H.type.1f42d4.1 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %Base.H.type: type = fn_type @Base.H [concrete]
|
||||
// CHECK:STDOUT: %Base.H: %Base.H.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %Derived.H.type.1f42d4.2: type = fn_type @Derived.H.loc9_30.2 [concrete]
|
||||
// CHECK:STDOUT: %Derived.H.a6796b.2: %Derived.H.type.1f42d4.2 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %Derived.vtable_decl: ref %ptr.454 = vtable_decl @Derived.vtable [concrete]
|
||||
// CHECK:STDOUT: %struct_type.base.507: type = struct_type {.base: %Base} [concrete]
|
||||
// CHECK:STDOUT: %complete_type.d6b: <witness> = complete_type_witness %struct_type.base.507 [concrete]
|
||||
@@ -676,6 +678,7 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: import Modifiers//default
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Modifiers.Base: type = import_ref Modifiers//default, Base, loaded [concrete = constants.%Base]
|
||||
// CHECK:STDOUT: %Base.H.decl: %Base.H.type = fn_decl @Base.H [concrete = constants.%Base.H] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
@@ -686,7 +689,7 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: %Modifiers.ref: <namespace> = name_ref Modifiers, imports.%Modifiers [concrete = imports.%Modifiers]
|
||||
// CHECK:STDOUT: %Base.ref: type = name_ref Base, imports.%Modifiers.Base [concrete = constants.%Base]
|
||||
// CHECK:STDOUT: %.loc8: %Derived.elem = base_decl %Base.ref, element0 [concrete]
|
||||
// CHECK:STDOUT: %Derived.H.decl: %Derived.H.type = fn_decl @Derived.H [concrete = constants.%Derived.H] {
|
||||
// CHECK:STDOUT: %Derived.H.decl.loc9_30.1: %Derived.H.type.1f42d4.1 = fn_decl @Derived.H.loc9_30.1 [concrete = constants.%Derived.H.a6796b.1] {
|
||||
// CHECK:STDOUT: %self.param_patt: %pattern_type.746 = value_param_pattern [concrete]
|
||||
// CHECK:STDOUT: %self.patt: %pattern_type.746 = at_binding_pattern self, %self.param_patt [concrete]
|
||||
// CHECK:STDOUT: } {
|
||||
@@ -694,6 +697,11 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%Derived [concrete = constants.%Derived]
|
||||
// CHECK:STDOUT: %self: %Derived = value_binding self, %self.param
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Derived.H.decl.loc9_30.2: %Derived.H.type.1f42d4.2 = fn_decl @Derived.H.loc9_30.2 [concrete = constants.%Derived.H.a6796b.2] {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %vtable_decl: ref %ptr.454 = vtable_decl @Derived.vtable [concrete = constants.%Derived.vtable_decl]
|
||||
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness constants.%struct_type.base.507 [concrete = constants.%complete_type.d6b]
|
||||
// CHECK:STDOUT: complete_type_witness = %complete_type
|
||||
@@ -703,7 +711,7 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: .Self = constants.%Derived
|
||||
// CHECK:STDOUT: .Modifiers = <poisoned>
|
||||
// CHECK:STDOUT: .base = %.loc8
|
||||
// CHECK:STDOUT: .H [hidden] = %Derived.H.decl
|
||||
// CHECK:STDOUT: .H [hidden] = %Derived.H.decl.loc9_30.1
|
||||
// CHECK:STDOUT: extend %Base.ref
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
@@ -712,10 +720,21 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: vtable @Derived.vtable {
|
||||
// CHECK:STDOUT: @Derived.%Derived.H.decl
|
||||
// CHECK:STDOUT: @Derived.%Derived.H.decl.loc9_30.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: override fn @Derived.H(%self.param: %Derived);
|
||||
// CHECK:STDOUT: override fn @Derived.H.loc9_30.1(%self.param: %Derived);
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: override fn @Derived.H.loc9_30.2(%self.param: %Base) [thunk @Derived.%Derived.H.decl.loc9_30.1 for imports.%Base.H.decl] {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %H.ref: %Derived.H.type.1f42d4.1 = name_ref H, @Derived.%Derived.H.decl.loc9_30.1 [concrete = constants.%Derived.H.a6796b.1]
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %.loc9_30.1: ref %Derived = enclosing_class_access %.1, element0
|
||||
// CHECK:STDOUT: %.loc9_30.2: %Derived = acquire_value %.loc9_30.1
|
||||
// CHECK:STDOUT: %Derived.H.bound: <bound method> = bound_method %.loc9_30.2, %H.ref
|
||||
// CHECK:STDOUT: %Derived.H.call: init %empty_tuple.type = call %Derived.H.bound(%.loc9_30.2)
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Use() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
@@ -994,17 +1013,22 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: --- abstract_impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %AbstractBase: type = class_type @AbstractBase [concrete]
|
||||
// CHECK:STDOUT: %AbstractBase.F.type: type = fn_type @AbstractBase.F [concrete]
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %AbstractBase.F: %AbstractBase.F.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %AbstractIntermediate: type = class_type @AbstractIntermediate [concrete]
|
||||
// CHECK:STDOUT: %Derived: type = class_type @Derived [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.746: type = pattern_type %Derived [concrete]
|
||||
// CHECK:STDOUT: %Derived.F.type: type = fn_type @Derived.F [concrete]
|
||||
// CHECK:STDOUT: %Derived.F: %Derived.F.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %Derived.F.type.48cdab.1: type = fn_type @Derived.F.loc15_30.1 [concrete]
|
||||
// CHECK:STDOUT: %Derived.F.bd5be1.1: %Derived.F.type.48cdab.1 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %Derived.F.type.48cdab.2: type = fn_type @Derived.F.loc15_30.2 [concrete]
|
||||
// CHECK:STDOUT: %Derived.F.bd5be1.2: %Derived.F.type.48cdab.2 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @Derived {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %Derived.F.decl: %Derived.F.type = fn_decl @Derived.F [concrete = constants.%Derived.F] {
|
||||
// CHECK:STDOUT: %Derived.F.decl.loc15_30.1: %Derived.F.type.48cdab.1 = fn_decl @Derived.F.loc15_30.1 [concrete = constants.%Derived.F.bd5be1.1] {
|
||||
// CHECK:STDOUT: %self.param_patt: %pattern_type.746 = value_param_pattern [concrete]
|
||||
// CHECK:STDOUT: %self.patt: %pattern_type.746 = at_binding_pattern self, %self.param_patt [concrete]
|
||||
// CHECK:STDOUT: } {
|
||||
@@ -1012,6 +1036,11 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%Derived [concrete = constants.%Derived]
|
||||
// CHECK:STDOUT: %self: %Derived = value_binding self, %self.param
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Derived.F.decl.loc15_30.2: %Derived.F.type.48cdab.2 = fn_decl @Derived.F.loc15_30.2 [concrete = constants.%Derived.F.bd5be1.2] {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: complete_type_witness = %complete_type
|
||||
// CHECK:STDOUT: vtable_decl = %vtable_decl
|
||||
@@ -1020,7 +1049,7 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: .Self = constants.%Derived
|
||||
// CHECK:STDOUT: .AbstractIntermediate = <poisoned>
|
||||
// CHECK:STDOUT: .base = %.loc13
|
||||
// CHECK:STDOUT: .F [hidden] = %Derived.F.decl
|
||||
// CHECK:STDOUT: .F [hidden] = %Derived.F.decl.loc15_30.1
|
||||
// CHECK:STDOUT: extend %AbstractIntermediate.ref
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
@@ -1033,25 +1062,42 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: vtable @Derived.vtable {
|
||||
// CHECK:STDOUT: @Derived.%Derived.F.decl
|
||||
// CHECK:STDOUT: @Derived.%Derived.F.decl.loc15_30.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: override fn @Derived.F(%self.param: %Derived);
|
||||
// CHECK:STDOUT: override fn @Derived.F.loc15_30.1(%self.param: %Derived);
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: override fn @Derived.F.loc15_30.2(%self.param: %AbstractBase) [thunk @Derived.%Derived.F.decl.loc15_30.1 for @AbstractBase.%AbstractBase.F.decl] {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %F.ref: %Derived.F.type.48cdab.1 = name_ref F, @Derived.%Derived.F.decl.loc15_30.1 [concrete = constants.%Derived.F.bd5be1.1]
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %.loc15_30.1: ref %AbstractIntermediate = enclosing_class_access %.loc5, element0
|
||||
// CHECK:STDOUT: %.loc15_30.2: ref %Derived = enclosing_class_access %.loc15_30.1, element0
|
||||
// CHECK:STDOUT: %.loc15_30.3: %Derived = acquire_value %.loc15_30.2
|
||||
// CHECK:STDOUT: %Derived.F.bound: <bound method> = bound_method %.loc15_30.3, %F.ref
|
||||
// CHECK:STDOUT: %Derived.F.call: init %empty_tuple.type = call %Derived.F.bound(%.loc15_30.3)
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- virtual_impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %VirtualBase: type = class_type @VirtualBase [concrete]
|
||||
// CHECK:STDOUT: %VirtualBase.F.type: type = fn_type @VirtualBase.F [concrete]
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %VirtualBase.F: %VirtualBase.F.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %VirtualIntermediate: type = class_type @VirtualIntermediate [concrete]
|
||||
// CHECK:STDOUT: %Derived: type = class_type @Derived [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.746: type = pattern_type %Derived [concrete]
|
||||
// CHECK:STDOUT: %Derived.F.type: type = fn_type @Derived.F [concrete]
|
||||
// CHECK:STDOUT: %Derived.F: %Derived.F.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %Derived.F.type.48cdab.1: type = fn_type @Derived.F.loc15_30.1 [concrete]
|
||||
// CHECK:STDOUT: %Derived.F.bd5be1.1: %Derived.F.type.48cdab.1 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %Derived.F.type.48cdab.2: type = fn_type @Derived.F.loc15_30.2 [concrete]
|
||||
// CHECK:STDOUT: %Derived.F.bd5be1.2: %Derived.F.type.48cdab.2 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @Derived {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %Derived.F.decl: %Derived.F.type = fn_decl @Derived.F [concrete = constants.%Derived.F] {
|
||||
// CHECK:STDOUT: %Derived.F.decl.loc15_30.1: %Derived.F.type.48cdab.1 = fn_decl @Derived.F.loc15_30.1 [concrete = constants.%Derived.F.bd5be1.1] {
|
||||
// CHECK:STDOUT: %self.param_patt: %pattern_type.746 = value_param_pattern [concrete]
|
||||
// CHECK:STDOUT: %self.patt: %pattern_type.746 = at_binding_pattern self, %self.param_patt [concrete]
|
||||
// CHECK:STDOUT: } {
|
||||
@@ -1059,6 +1105,11 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%Derived [concrete = constants.%Derived]
|
||||
// CHECK:STDOUT: %self: %Derived = value_binding self, %self.param
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Derived.F.decl.loc15_30.2: %Derived.F.type.48cdab.2 = fn_decl @Derived.F.loc15_30.2 [concrete = constants.%Derived.F.bd5be1.2] {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: complete_type_witness = %complete_type
|
||||
// CHECK:STDOUT: vtable_decl = %vtable_decl
|
||||
@@ -1067,7 +1118,7 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: .Self = constants.%Derived
|
||||
// CHECK:STDOUT: .VirtualIntermediate = <poisoned>
|
||||
// CHECK:STDOUT: .base = %.loc13
|
||||
// CHECK:STDOUT: .F [hidden] = %Derived.F.decl
|
||||
// CHECK:STDOUT: .F [hidden] = %Derived.F.decl.loc15_30.1
|
||||
// CHECK:STDOUT: extend %VirtualIntermediate.ref
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
@@ -1080,10 +1131,22 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: vtable @Derived.vtable {
|
||||
// CHECK:STDOUT: @Derived.%Derived.F.decl
|
||||
// CHECK:STDOUT: @Derived.%Derived.F.decl.loc15_30.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: override fn @Derived.F(%self.param: %Derived);
|
||||
// CHECK:STDOUT: override fn @Derived.F.loc15_30.1(%self.param: %Derived);
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: override fn @Derived.F.loc15_30.2(%self.param: %VirtualBase) [thunk @Derived.%Derived.F.decl.loc15_30.1 for @VirtualBase.%VirtualBase.F.decl] {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %F.ref: %Derived.F.type.48cdab.1 = name_ref F, @Derived.%Derived.F.decl.loc15_30.1 [concrete = constants.%Derived.F.bd5be1.1]
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %.loc15_30.1: ref %VirtualIntermediate = enclosing_class_access %.loc5, element0
|
||||
// CHECK:STDOUT: %.loc15_30.2: ref %Derived = enclosing_class_access %.loc15_30.1, element0
|
||||
// CHECK:STDOUT: %.loc15_30.3: %Derived = acquire_value %.loc15_30.2
|
||||
// CHECK:STDOUT: %Derived.F.bound: <bound method> = bound_method %.loc15_30.3, %F.ref
|
||||
// CHECK:STDOUT: %Derived.F.call: init %empty_tuple.type = call %Derived.F.bound(%.loc15_30.3)
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- impl_conversion.carbon
|
||||
// CHECK:STDOUT:
|
||||
@@ -1098,6 +1161,7 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: %T2.as.ImplicitAs.impl.Convert: %T2.as.ImplicitAs.impl.Convert.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.a74 = facet_value %T2, (%ImplicitAs.impl_witness) [concrete]
|
||||
// CHECK:STDOUT: %ImplicitAs.WithSelf.Convert.type.00a: type = fn_type @ImplicitAs.WithSelf.Convert, @ImplicitAs.WithSelf(%T1, %ImplicitAs.facet) [concrete]
|
||||
// CHECK:STDOUT: %Base: type = class_type @Base [concrete]
|
||||
// CHECK:STDOUT: %Derived: type = class_type @Derived [concrete]
|
||||
// CHECK:STDOUT: %.617: Core.Form = init_form %T2 [concrete]
|
||||
// CHECK:STDOUT: %Derived.F.type.48cdab.1: type = fn_type @Derived.F.loc27 [concrete]
|
||||
@@ -1149,22 +1213,25 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: @Derived.%Derived.F.decl.loc23_36.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: override fn @Derived.F.loc23(%self.param: %Derived) -> out %return.param: %T1 [thunk @Derived.%Derived.F.decl.loc23_36.1 for @Base.%Base.F.decl] {
|
||||
// CHECK:STDOUT: override fn @Derived.F.loc23(%self.param: %Base) -> out %return.param: %T1 [thunk @Derived.%Derived.F.decl.loc23_36.1 for @Base.%Base.F.decl] {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %F.ref: %Derived.F.type.48cdab.1 = name_ref F, @Derived.%Derived.F.decl.loc23_36.1 [concrete = constants.%Derived.F.bd5be1.1]
|
||||
// CHECK:STDOUT: %Derived.F.bound: <bound method> = bound_method %self.param, %F.ref
|
||||
// CHECK:STDOUT: %.loc23_36.1: ref %T2 = temporary_storage
|
||||
// CHECK:STDOUT: %Derived.F.call: init %T2 to %.loc23_36.1 = call %Derived.F.bound(%self.param)
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %.loc23_36.1: ref %Derived = enclosing_class_access %.loc17_20, element0
|
||||
// CHECK:STDOUT: %.loc23_36.2: %Derived = acquire_value %.loc23_36.1
|
||||
// CHECK:STDOUT: %Derived.F.bound: <bound method> = bound_method %.loc23_36.2, %F.ref
|
||||
// CHECK:STDOUT: %.loc23_36.3: ref %T2 = temporary_storage
|
||||
// CHECK:STDOUT: %Derived.F.call: init %T2 to %.loc23_36.3 = call %Derived.F.bound(%.loc23_36.2)
|
||||
// CHECK:STDOUT: %impl.elem0: %.fd2 = impl_witness_access constants.%ImplicitAs.impl_witness, element0 [concrete = constants.%T2.as.ImplicitAs.impl.Convert]
|
||||
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %Derived.F.call, %impl.elem0
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %.loc23_36.2: ref %T2 = temporary %.loc23_36.1, %Derived.F.call
|
||||
// CHECK:STDOUT: %.loc23_36.3: %T2 = acquire_value %.loc23_36.2
|
||||
// CHECK:STDOUT: %T2.as.ImplicitAs.impl.Convert.call: init %T1 to %.loc17 = call %bound_method(%.loc23_36.3)
|
||||
// CHECK:STDOUT: %.loc23_36.4: init %T1 = converted %Derived.F.call, %T2.as.ImplicitAs.impl.Convert.call
|
||||
// CHECK:STDOUT: %Destroy.Op.bound: <bound method> = bound_method %.loc23_36.2, constants.%Destroy.Op.1a2547.2
|
||||
// CHECK:STDOUT: %Destroy.Op.call: init %empty_tuple.type = call %Destroy.Op.bound(%.loc23_36.2)
|
||||
// CHECK:STDOUT: return %.loc23_36.4 to %return.param
|
||||
// CHECK:STDOUT: %.loc23_36.4: ref %T2 = temporary %.loc23_36.3, %Derived.F.call
|
||||
// CHECK:STDOUT: %.loc23_36.5: %T2 = acquire_value %.loc23_36.4
|
||||
// CHECK:STDOUT: %T2.as.ImplicitAs.impl.Convert.call: init %T1 to %.loc17_33 = call %bound_method(%.loc23_36.5)
|
||||
// CHECK:STDOUT: %.loc23_36.6: init %T1 = converted %Derived.F.call, %T2.as.ImplicitAs.impl.Convert.call
|
||||
// CHECK:STDOUT: %Destroy.Op.bound: <bound method> = bound_method %.loc23_36.4, constants.%Destroy.Op.1a2547.2
|
||||
// CHECK:STDOUT: %Destroy.Op.call: init %empty_tuple.type = call %Destroy.Op.bound(%.loc23_36.4)
|
||||
// CHECK:STDOUT: return %.loc23_36.6 to %return.param
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Destroy.Op.loc23_36.1(%self.param: ref %empty_struct_type) = "no_op";
|
||||
@@ -1346,6 +1413,7 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %Base.type: type = generic_class_type @Base [concrete]
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %Base.generic: %Base.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %T1: type = class_type @T1 [concrete]
|
||||
// CHECK:STDOUT: %D1: type = class_type @D1 [concrete]
|
||||
@@ -1353,13 +1421,15 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: %ptr.2ee: type = ptr_type %Base.5b2 [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.e0f: type = pattern_type %ptr.2ee [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.c35: type = pattern_type %D1 [concrete]
|
||||
// CHECK:STDOUT: %D1.F.type: type = fn_type @D1.F [concrete]
|
||||
// CHECK:STDOUT: %D1.F: %D1.F.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %D1.F.type.48cdab.1: type = fn_type @D1.F.loc11_57.1 [concrete]
|
||||
// CHECK:STDOUT: %D1.F.bd5be1.1: %D1.F.type.48cdab.1 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %D1.F.type.48cdab.2: type = fn_type @D1.F.loc11_57.2 [concrete]
|
||||
// CHECK:STDOUT: %D1.F.bd5be1.2: %D1.F.type.48cdab.2 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @D1 {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %D1.F.decl: %D1.F.type = fn_decl @D1.F [concrete = constants.%D1.F] {
|
||||
// CHECK:STDOUT: %D1.F.decl.loc11_57.1: %D1.F.type.48cdab.1 = fn_decl @D1.F.loc11_57.1 [concrete = constants.%D1.F.bd5be1.1] {
|
||||
// CHECK:STDOUT: %self.param_patt: %pattern_type.c35 = value_param_pattern [concrete]
|
||||
// CHECK:STDOUT: %self.patt: %pattern_type.c35 = at_binding_pattern self, %self.param_patt [concrete]
|
||||
// CHECK:STDOUT: %t.param_patt: %pattern_type.e0f = value_param_pattern [concrete]
|
||||
@@ -1377,6 +1447,11 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %t: %ptr.2ee = value_binding t, %t.param
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %D1.F.decl.loc11_57.2: %D1.F.type.48cdab.2 = fn_decl @D1.F.loc11_57.2 [concrete = constants.%D1.F.bd5be1.2] {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: complete_type_witness = %complete_type
|
||||
// CHECK:STDOUT: vtable_decl = %vtable_decl
|
||||
@@ -1386,7 +1461,7 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: .Base = <poisoned>
|
||||
// CHECK:STDOUT: .T1 = <poisoned>
|
||||
// CHECK:STDOUT: .base = %.loc9
|
||||
// CHECK:STDOUT: .F [hidden] = %D1.F.decl
|
||||
// CHECK:STDOUT: .F [hidden] = %D1.F.decl.loc11_57.1
|
||||
// CHECK:STDOUT: extend %Base
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
@@ -1395,32 +1470,48 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: vtable @D1.vtable {
|
||||
// CHECK:STDOUT: @D1.%D1.F.decl
|
||||
// CHECK:STDOUT: @D1.%D1.F.decl.loc11_57.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: override fn @D1.F(%self.param: %D1, %t.param: %ptr.2ee) {
|
||||
// CHECK:STDOUT: override fn @D1.F.loc11_57.1(%self.param: %D1, %t.param: %ptr.2ee) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: override fn @D1.F.loc11_57.2(%self.param: %Base.5b2, %t.param: %ptr.2ee) [thunk @D1.%D1.F.decl.loc11_57.1 for @Base.%Base.F.decl, @Base.F(constants.%T1)] {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %F.ref: %D1.F.type.48cdab.1 = name_ref F, @D1.%D1.F.decl.loc11_57.1 [concrete = constants.%D1.F.bd5be1.1]
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %.loc11_57.1: ref %D1 = enclosing_class_access %.loc5, element0
|
||||
// CHECK:STDOUT: %.loc11_57.2: %D1 = acquire_value %.loc11_57.1
|
||||
// CHECK:STDOUT: %D1.F.bound: <bound method> = bound_method %.loc11_57.2, %F.ref
|
||||
// CHECK:STDOUT: %D1.F.call: init %empty_tuple.type = call %D1.F.bound(%.loc11_57.2, %t.param)
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- impl_generic_generic.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %T: type = symbolic_binding T, 0 [symbolic]
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %Derived: type = class_type @Derived, @Derived(%T) [symbolic]
|
||||
// CHECK:STDOUT: %ptr.e8f: type = ptr_type %T [symbolic]
|
||||
// CHECK:STDOUT: %Base.99a: type = class_type @Base, @Base(%ptr.e8f) [symbolic]
|
||||
// CHECK:STDOUT: %pattern_type.bdc: type = pattern_type %Base.99a [symbolic]
|
||||
// CHECK:STDOUT: %pattern_type.4f4: type = pattern_type %ptr.e8f [symbolic]
|
||||
// CHECK:STDOUT: %require_complete.29f: <witness> = require_complete_type %Base.99a [symbolic]
|
||||
// CHECK:STDOUT: %Derived.elem: type = unbound_element_type %Derived, %Base.99a [symbolic]
|
||||
// CHECK:STDOUT: %pattern_type.839: type = pattern_type %Derived [symbolic]
|
||||
// CHECK:STDOUT: %Derived.F.type: type = fn_type @Derived.F, @Derived(%T) [symbolic]
|
||||
// CHECK:STDOUT: %Derived.F: %Derived.F.type = struct_value () [symbolic]
|
||||
// CHECK:STDOUT: %Derived.F.specific_fn: <specific function> = specific_function %Derived.F, @Derived.F(%T) [symbolic]
|
||||
// CHECK:STDOUT: %Derived.F.type.77405e.1: type = fn_type @Derived.F.loc10_50.1, @Derived(%T) [symbolic]
|
||||
// CHECK:STDOUT: %Derived.F.d85493.1: %Derived.F.type.77405e.1 = struct_value () [symbolic]
|
||||
// CHECK:STDOUT: %Derived.F.type.77405e.2: type = fn_type @Derived.F.loc10_50.2, @Derived(%T) [symbolic]
|
||||
// CHECK:STDOUT: %Derived.F.d85493.2: %Derived.F.type.77405e.2 = struct_value () [symbolic]
|
||||
// CHECK:STDOUT: %Derived.F.specific_fn.822c1a.1: <specific function> = specific_function %Derived.F.d85493.2, @Derived.F.loc10_50.2(%T) [symbolic]
|
||||
// CHECK:STDOUT: %struct_type.base.619: type = struct_type {.base: %Base.99a} [symbolic]
|
||||
// CHECK:STDOUT: %complete_type.db5: <witness> = complete_type_witness %struct_type.base.619 [symbolic]
|
||||
// CHECK:STDOUT: %require_complete.1e7: <witness> = require_complete_type %Derived [symbolic]
|
||||
// CHECK:STDOUT: %require_complete.ef1: <witness> = require_complete_type %ptr.e8f [symbolic]
|
||||
// CHECK:STDOUT: %Derived.F.specific_fn.822c1a.2: <specific function> = specific_function %Derived.F.d85493.1, @Derived.F.loc10_50.1(%T) [symbolic]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: generic class @Derived(%T.loc7_16.2: type) {
|
||||
@@ -1428,30 +1519,37 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !definition:
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %Derived.F.type: type = fn_type @Derived.F, @Derived(%T.loc7_16.1) [symbolic = %Derived.F.type (constants.%Derived.F.type)]
|
||||
// CHECK:STDOUT: %Derived.F: @Derived.%Derived.F.type (%Derived.F.type) = struct_value () [symbolic = %Derived.F (constants.%Derived.F)]
|
||||
// CHECK:STDOUT: %Derived.F.type.loc10_50.1: type = fn_type @Derived.F.loc10_50.1, @Derived(%T.loc7_16.1) [symbolic = %Derived.F.type.loc10_50.1 (constants.%Derived.F.type.77405e.1)]
|
||||
// CHECK:STDOUT: %Derived.F.loc10_50.1: @Derived.%Derived.F.type.loc10_50.1 (%Derived.F.type.77405e.1) = struct_value () [symbolic = %Derived.F.loc10_50.1 (constants.%Derived.F.d85493.1)]
|
||||
// CHECK:STDOUT: %Derived.F.type.loc10_50.2: type = fn_type @Derived.F.loc10_50.2, @Derived(%T.loc7_16.1) [symbolic = %Derived.F.type.loc10_50.2 (constants.%Derived.F.type.77405e.2)]
|
||||
// CHECK:STDOUT: %Derived.F.loc10_50.2: @Derived.%Derived.F.type.loc10_50.2 (%Derived.F.type.77405e.2) = struct_value () [symbolic = %Derived.F.loc10_50.2 (constants.%Derived.F.d85493.2)]
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %Derived.F.decl: @Derived.%Derived.F.type (%Derived.F.type) = fn_decl @Derived.F [symbolic = @Derived.%Derived.F (constants.%Derived.F)] {
|
||||
// CHECK:STDOUT: %self.param_patt: @Derived.F.%pattern_type.loc10_28 (%pattern_type.839) = value_param_pattern [concrete]
|
||||
// CHECK:STDOUT: %self.patt: @Derived.F.%pattern_type.loc10_28 (%pattern_type.839) = at_binding_pattern self, %self.param_patt [concrete]
|
||||
// CHECK:STDOUT: %t.param_patt: @Derived.F.%pattern_type.loc10_44 (%pattern_type.4f4) = value_param_pattern [concrete]
|
||||
// CHECK:STDOUT: %t.patt: @Derived.F.%pattern_type.loc10_44 (%pattern_type.4f4) = at_binding_pattern t, %t.param_patt [concrete]
|
||||
// CHECK:STDOUT: %Derived.F.decl.loc10_50.1: @Derived.%Derived.F.type.loc10_50.1 (%Derived.F.type.77405e.1) = fn_decl @Derived.F.loc10_50.1 [symbolic = @Derived.%Derived.F.loc10_50.1 (constants.%Derived.F.d85493.1)] {
|
||||
// CHECK:STDOUT: %self.param_patt: @Derived.F.loc10_50.1.%pattern_type.loc10_28 (%pattern_type.839) = value_param_pattern [concrete]
|
||||
// CHECK:STDOUT: %self.patt: @Derived.F.loc10_50.1.%pattern_type.loc10_28 (%pattern_type.839) = at_binding_pattern self, %self.param_patt [concrete]
|
||||
// CHECK:STDOUT: %t.param_patt: @Derived.F.loc10_50.1.%pattern_type.loc10_44 (%pattern_type.4f4) = value_param_pattern [concrete]
|
||||
// CHECK:STDOUT: %t.patt: @Derived.F.loc10_50.1.%pattern_type.loc10_44 (%pattern_type.4f4) = at_binding_pattern t, %t.param_patt [concrete]
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: %self.param: @Derived.F.%Derived (%Derived) = value_param call_param0
|
||||
// CHECK:STDOUT: %self.param: @Derived.F.loc10_50.1.%Derived (%Derived) = value_param call_param0
|
||||
// CHECK:STDOUT: %.loc10_30.1: type = splice_block %Self.ref [symbolic = %Derived (constants.%Derived)] {
|
||||
// CHECK:STDOUT: %.loc10_30.2: type = specific_constant constants.%Derived, @Derived(constants.%T) [symbolic = %Derived (constants.%Derived)]
|
||||
// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc10_30.2 [symbolic = %Derived (constants.%Derived)]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %self: @Derived.F.%Derived (%Derived) = value_binding self, %self.param
|
||||
// CHECK:STDOUT: %t.param: @Derived.F.%ptr.loc10_47.1 (%ptr.e8f) = value_param call_param1
|
||||
// CHECK:STDOUT: %self: @Derived.F.loc10_50.1.%Derived (%Derived) = value_binding self, %self.param
|
||||
// CHECK:STDOUT: %t.param: @Derived.F.loc10_50.1.%ptr.loc10_47.1 (%ptr.e8f) = value_param call_param1
|
||||
// CHECK:STDOUT: %.loc10_47: type = splice_block %ptr.loc10_47.2 [symbolic = %ptr.loc10_47.1 (constants.%ptr.e8f)] {
|
||||
// CHECK:STDOUT: %T.ref: type = name_ref T, @Derived.%T.loc7_16.2 [symbolic = %T (constants.%T)]
|
||||
// CHECK:STDOUT: %ptr.loc10_47.2: type = ptr_type %T.ref [symbolic = %ptr.loc10_47.1 (constants.%ptr.e8f)]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %t: @Derived.F.%ptr.loc10_47.1 (%ptr.e8f) = value_binding t, %t.param
|
||||
// CHECK:STDOUT: %t: @Derived.F.loc10_50.1.%ptr.loc10_47.1 (%ptr.e8f) = value_binding t, %t.param
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Derived.F.decl.loc10_50.2: @Derived.%Derived.F.type.loc10_50.2 (%Derived.F.type.77405e.2) = fn_decl @Derived.F.loc10_50.2 [symbolic = @Derived.%Derived.F.loc10_50.2 (constants.%Derived.F.d85493.2)] {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: complete_type_witness = %complete_type.loc12_1.1
|
||||
@@ -1462,7 +1560,7 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: .Base = <poisoned>
|
||||
// CHECK:STDOUT: .T = <poisoned>
|
||||
// CHECK:STDOUT: .base = %.loc8
|
||||
// CHECK:STDOUT: .F [hidden] = %Derived.F.decl
|
||||
// CHECK:STDOUT: .F [hidden] = %Derived.F.decl.loc10_50.1
|
||||
// CHECK:STDOUT: extend %Base.loc8_23.1
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
@@ -1475,7 +1573,7 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: @Derived.%Derived.F.specific_fn.loc12_1.1
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: generic override fn @Derived.F(@Derived.%T.loc7_16.2: type) {
|
||||
// CHECK:STDOUT: generic override fn @Derived.F.loc10_50.1(@Derived.%T.loc7_16.2: type) {
|
||||
// CHECK:STDOUT: %T: type = symbolic_binding T, 0 [symbolic = %T (constants.%T)]
|
||||
// CHECK:STDOUT: %Derived: type = class_type @Derived, @Derived(%T) [symbolic = %Derived (constants.%Derived)]
|
||||
// CHECK:STDOUT: %pattern_type.loc10_28: type = pattern_type %Derived [symbolic = %pattern_type.loc10_28 (constants.%pattern_type.839)]
|
||||
@@ -1486,12 +1584,37 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: %require_complete.loc10_28: <witness> = require_complete_type %Derived [symbolic = %require_complete.loc10_28 (constants.%require_complete.1e7)]
|
||||
// CHECK:STDOUT: %require_complete.loc10_44: <witness> = require_complete_type %ptr.loc10_47.1 [symbolic = %require_complete.loc10_44 (constants.%require_complete.ef1)]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: override fn(%self.param: @Derived.F.%Derived (%Derived), %t.param: @Derived.F.%ptr.loc10_47.1 (%ptr.e8f)) {
|
||||
// CHECK:STDOUT: override fn(%self.param: @Derived.F.loc10_50.1.%Derived (%Derived), %t.param: @Derived.F.loc10_50.1.%ptr.loc10_47.1 (%ptr.e8f)) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: generic override fn @Derived.F.loc10_50.2(@Derived.%T.loc7_16.2: type) {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !definition:
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %Derived.F.type: type = fn_type @Derived.F.loc10_50.1, @Derived(%T) [symbolic = %Derived.F.type (constants.%Derived.F.type.77405e.1)]
|
||||
// CHECK:STDOUT: %Derived.F: @Derived.F.loc10_50.2.%Derived.F.type (%Derived.F.type.77405e.1) = struct_value () [symbolic = %Derived.F (constants.%Derived.F.d85493.1)]
|
||||
// CHECK:STDOUT: %Derived: type = class_type @Derived, @Derived(%T) [symbolic = %Derived (constants.%Derived)]
|
||||
// CHECK:STDOUT: %Derived.F.specific_fn.loc10_50.2: <specific function> = specific_function %Derived.F, @Derived.F.loc10_50.1(%T) [symbolic = %Derived.F.specific_fn.loc10_50.2 (constants.%Derived.F.specific_fn.822c1a.2)]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: override fn(%self.param: @Derived.F.loc10_50.2.%Base (%Base.99a), %t.param: @Derived.F.loc10_50.2.%ptr (%ptr.e8f)) [thunk @Derived.%Derived.F.decl.loc10_50.1 for @Base.%Base.F.decl, @Base.F(constants.%ptr.e8f)] {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %.loc10_50.1: @Derived.F.loc10_50.2.%Derived.F.type (%Derived.F.type.77405e.1) = specific_constant @Derived.%Derived.F.decl.loc10_50.1, @Derived(constants.%T) [symbolic = %Derived.F (constants.%Derived.F.d85493.1)]
|
||||
// CHECK:STDOUT: %F.ref: @Derived.F.loc10_50.2.%Derived.F.type (%Derived.F.type.77405e.1) = name_ref F, %.loc10_50.1 [symbolic = %Derived.F (constants.%Derived.F.d85493.1)]
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %.loc10_50.2: ref @Derived.F.loc10_50.2.%Derived (%Derived) = enclosing_class_access %.loc5, element0
|
||||
// CHECK:STDOUT: %.loc10_50.3: @Derived.F.loc10_50.2.%Derived (%Derived) = acquire_value %.loc10_50.2
|
||||
// CHECK:STDOUT: %Derived.F.bound: <bound method> = bound_method %.loc10_50.3, %F.ref
|
||||
// CHECK:STDOUT: %Derived.F.specific_fn.loc10_50.1: <specific function> = specific_function %F.ref, @Derived.F.loc10_50.1(constants.%T) [symbolic = %Derived.F.specific_fn.loc10_50.2 (constants.%Derived.F.specific_fn.822c1a.2)]
|
||||
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc10_50.3, %Derived.F.specific_fn.loc10_50.1
|
||||
// CHECK:STDOUT: %Derived.F.call: init %empty_tuple.type = call %bound_method(%.loc10_50.3, %t.param)
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific @Derived(constants.%T) {
|
||||
// CHECK:STDOUT: %T.loc7_16.1 => constants.%T
|
||||
// CHECK:STDOUT:
|
||||
@@ -1501,14 +1624,16 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: %require_complete => constants.%require_complete.29f
|
||||
// CHECK:STDOUT: %Derived => constants.%Derived
|
||||
// CHECK:STDOUT: %Derived.elem => constants.%Derived.elem
|
||||
// CHECK:STDOUT: %Derived.F.type => constants.%Derived.F.type
|
||||
// CHECK:STDOUT: %Derived.F => constants.%Derived.F
|
||||
// CHECK:STDOUT: %Derived.F.specific_fn.loc12_1.2 => constants.%Derived.F.specific_fn
|
||||
// CHECK:STDOUT: %Derived.F.type.loc10_50.1 => constants.%Derived.F.type.77405e.1
|
||||
// CHECK:STDOUT: %Derived.F.loc10_50.1 => constants.%Derived.F.d85493.1
|
||||
// CHECK:STDOUT: %Derived.F.type.loc10_50.2 => constants.%Derived.F.type.77405e.2
|
||||
// CHECK:STDOUT: %Derived.F.loc10_50.2 => constants.%Derived.F.d85493.2
|
||||
// CHECK:STDOUT: %Derived.F.specific_fn.loc12_1.2 => constants.%Derived.F.specific_fn.822c1a.1
|
||||
// CHECK:STDOUT: %struct_type.base => constants.%struct_type.base.619
|
||||
// CHECK:STDOUT: %complete_type.loc12_1.2 => constants.%complete_type.db5
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific @Derived.F(constants.%T) {
|
||||
// CHECK:STDOUT: specific @Derived.F.loc10_50.1(constants.%T) {
|
||||
// CHECK:STDOUT: %T => constants.%T
|
||||
// CHECK:STDOUT: %Derived => constants.%Derived
|
||||
// CHECK:STDOUT: %pattern_type.loc10_28 => constants.%pattern_type.839
|
||||
@@ -1520,3 +1645,19 @@ class T2(G2:! type) {
|
||||
// CHECK:STDOUT: %require_complete.loc10_44 => constants.%require_complete.ef1
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific @Derived.F.loc10_50.2(constants.%T) {
|
||||
// CHECK:STDOUT: %T => constants.%T
|
||||
// CHECK:STDOUT: %ptr => constants.%ptr.e8f
|
||||
// CHECK:STDOUT: %Base => constants.%Base.99a
|
||||
// CHECK:STDOUT: %pattern_type.loc5_27 => constants.%pattern_type.bdc
|
||||
// CHECK:STDOUT: %pattern_type.loc5_43 => constants.%pattern_type.4f4
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !definition:
|
||||
// CHECK:STDOUT: %require_complete.loc5_27 => constants.%require_complete.29f
|
||||
// CHECK:STDOUT: %require_complete.loc5_43 => constants.%require_complete.ef1
|
||||
// CHECK:STDOUT: %Derived.F.type => constants.%Derived.F.type.77405e.1
|
||||
// CHECK:STDOUT: %Derived.F => constants.%Derived.F.d85493.1
|
||||
// CHECK:STDOUT: %Derived => constants.%Derived
|
||||
// CHECK:STDOUT: %Derived.F.specific_fn.loc10_50.2 => constants.%Derived.F.specific_fn.822c1a.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
|
||||
+42
-39
@@ -100,10 +100,8 @@ static auto CloneBindingPattern(Context& context, SemIR::InstId pattern_id,
|
||||
// Makes a copy of the given pattern instruction, substituting values from a
|
||||
// specific as needed. The resulting pattern behaves like a newly-created
|
||||
// pattern, so is suitable for running `CalleePatternMatch` against.
|
||||
static auto ClonePattern(
|
||||
Context& context, SemIR::SpecificId specific_id, SemIR::InstId pattern_id,
|
||||
SemIR::TypeId self_type_override_id = SemIR::TypeId::None)
|
||||
-> SemIR::InstId {
|
||||
static auto ClonePattern(Context& context, SemIR::SpecificId specific_id,
|
||||
SemIR::InstId pattern_id) -> SemIR::InstId {
|
||||
if (!pattern_id.has_value()) {
|
||||
return SemIR::InstId::None;
|
||||
}
|
||||
@@ -126,11 +124,6 @@ static auto ClonePattern(
|
||||
auto new_pattern_id = SemIR::InstId::None;
|
||||
if (auto binding = pattern.TryAs<SemIR::AnyBindingPattern>()) {
|
||||
auto type_id = get_type(pattern_id);
|
||||
if (self_type_override_id.has_value() &&
|
||||
context.entity_names().Get(binding->entity_name_id).name_id ==
|
||||
SemIR::NameId::SelfValue) {
|
||||
type_id = GetPatternType(context, self_type_override_id);
|
||||
}
|
||||
new_pattern_id =
|
||||
CloneBindingPattern(context, pattern_id, *binding, type_id);
|
||||
} else if (auto return_slot = pattern.TryAs<SemIR::ReturnSlotPattern>()) {
|
||||
@@ -178,16 +171,14 @@ static auto ClonePattern(
|
||||
}
|
||||
|
||||
static auto ClonePatternBlock(Context& context, SemIR::SpecificId specific_id,
|
||||
SemIR::InstBlockId inst_block_id,
|
||||
SemIR::TypeId self_type_override_id =
|
||||
SemIR::TypeId::None) -> SemIR::InstBlockId {
|
||||
SemIR::InstBlockId inst_block_id)
|
||||
-> SemIR::InstBlockId {
|
||||
if (!inst_block_id.has_value()) {
|
||||
return SemIR::InstBlockId::None;
|
||||
}
|
||||
return context.inst_blocks().Transform(
|
||||
inst_block_id, [&](SemIR::InstId inst_id) {
|
||||
return ClonePattern(context, specific_id, inst_id,
|
||||
self_type_override_id);
|
||||
return ClonePattern(context, specific_id, inst_id);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -217,7 +208,6 @@ static auto CloneTypeInstId(Context& context, SemIR::SpecificId specific_id,
|
||||
static auto CloneFunctionDecl(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::FunctionId signature_id,
|
||||
SemIR::SpecificId signature_specific_id,
|
||||
SemIR::TypeId signature_self_type_override_id,
|
||||
SemIR::FunctionId callee_id)
|
||||
-> std::pair<SemIR::FunctionId, SemIR::InstId> {
|
||||
StartGenericDecl(context);
|
||||
@@ -227,8 +217,7 @@ static auto CloneFunctionDecl(Context& context, SemIR::LocId loc_id,
|
||||
// Clone the signature.
|
||||
context.pattern_block_stack().Push();
|
||||
auto implicit_param_patterns_id = ClonePatternBlock(
|
||||
context, signature_specific_id, signature.implicit_param_patterns_id,
|
||||
signature_self_type_override_id);
|
||||
context, signature_specific_id, signature.implicit_param_patterns_id);
|
||||
auto param_patterns_id = ClonePatternBlock(context, signature_specific_id,
|
||||
signature.param_patterns_id);
|
||||
auto return_pattern_id =
|
||||
@@ -293,13 +282,19 @@ auto PerformThunkCall(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::FunctionId function_id,
|
||||
llvm::ArrayRef<SemIR::InstId> param_pattern_ids,
|
||||
llvm::ArrayRef<SemIR::InstId> call_arg_ids,
|
||||
SemIR::InstId callee_id) -> SemIR::InstId {
|
||||
SemIR::InstId callee_id,
|
||||
SemIR::TypeId override_self_type_id) -> SemIR::InstId {
|
||||
auto& function = context.functions().Get(function_id);
|
||||
|
||||
auto [args_vec, ignored_call_args] = ThunkPatternMatch(
|
||||
context, function.self_param_id, param_pattern_ids, call_arg_ids);
|
||||
llvm::ArrayRef<SemIR::InstId> args = args_vec;
|
||||
|
||||
if (override_self_type_id.has_value()) {
|
||||
args_vec.front() = UnsafeUndoConvert(context, loc_id, args_vec.front(),
|
||||
override_self_type_id);
|
||||
}
|
||||
|
||||
// If we have a self parameter, form `self.<callee_id>` if needed.
|
||||
// When calling a C++ constructor to implement `Copy`, or calling a C++
|
||||
// non-method operator to implement a Carbon operator, the interface has a
|
||||
@@ -318,11 +313,15 @@ auto PerformThunkCall(Context& context, SemIR::LocId loc_id,
|
||||
}
|
||||
|
||||
// Build a call to a function that forwards the arguments of the enclosing
|
||||
// function, for use when constructing a thunk.
|
||||
// function, for use when constructing a thunk. `param_pattern_ids` contains the
|
||||
// parameter patterns of `function_id`. If `override_self_type_id` is not
|
||||
// `None`, `callee_id` refers to a virtual function override declared in the
|
||||
// given type.
|
||||
static auto BuildThunkCall(Context& context, SemIR::FunctionId function_id,
|
||||
SemIR::InstId callee_id,
|
||||
llvm::ArrayRef<SemIR::InstId> param_pattern_ids,
|
||||
llvm::ArrayRef<SemIR::InstId> call_arg_ids)
|
||||
llvm::ArrayRef<SemIR::InstId> call_arg_ids,
|
||||
SemIR::TypeId override_self_type_id)
|
||||
-> SemIR::InstId {
|
||||
auto& function = context.functions().Get(function_id);
|
||||
|
||||
@@ -334,7 +333,7 @@ static auto BuildThunkCall(Context& context, SemIR::FunctionId function_id,
|
||||
callee_type.specific_id);
|
||||
|
||||
return PerformThunkCall(context, loc_id, function_id, param_pattern_ids,
|
||||
call_arg_ids, callee_id);
|
||||
call_arg_ids, callee_id, override_self_type_id);
|
||||
}
|
||||
|
||||
static auto StartThunkFunctionDefinition(Context& context,
|
||||
@@ -359,7 +358,8 @@ static auto BuildThunkDefinition(Context& context,
|
||||
SemIR::FunctionId signature_id,
|
||||
SemIR::FunctionId function_id,
|
||||
SemIR::InstId thunk_id,
|
||||
SemIR::InstId callee_id) -> void {
|
||||
SemIR::InstId callee_id,
|
||||
SemIR::TypeId override_self_type_id) -> void {
|
||||
// TODO: Improve the diagnostics produced here. Specifically, it would likely
|
||||
// be better for the primary error message to be that we tried to produce a
|
||||
// thunk because of a type mismatch, but couldn't, with notes explaining
|
||||
@@ -386,8 +386,9 @@ static auto BuildThunkDefinition(Context& context,
|
||||
}
|
||||
auto call_param_ids = context.inst_blocks().Get(function.call_params_id);
|
||||
|
||||
auto call_id = BuildThunkCall(context, function_id, callee_id,
|
||||
param_pattern_ids, call_param_ids);
|
||||
auto call_id =
|
||||
BuildThunkCall(context, function_id, callee_id, param_pattern_ids,
|
||||
call_param_ids, override_self_type_id);
|
||||
if (HasDeclaredReturnType(context, function_id)) {
|
||||
BuildReturnWithExpr(context, SemIR::LocId(callee_id), call_id);
|
||||
} else {
|
||||
@@ -425,7 +426,8 @@ auto BuildThunkDefinitionForExport(Context& context,
|
||||
}
|
||||
|
||||
auto call_id = BuildThunkCall(context, thunk_function_id, callee_id,
|
||||
param_pattern_ids, call_param_ids);
|
||||
param_pattern_ids, call_param_ids,
|
||||
/*override_self_type_id=*/SemIR::TypeId::None);
|
||||
if (thunk_has_return_param) {
|
||||
auto out_param_id =
|
||||
context.inst_blocks().Get(thunk_function.call_params_id).back();
|
||||
@@ -453,16 +455,16 @@ auto BuildThunkDefinition(Context& context,
|
||||
context.scope_stack().Restore(std::move(task.scope));
|
||||
|
||||
BuildThunkDefinition(context, task.info.signature_id, task.info.function_id,
|
||||
task.info.decl_id, task.info.callee_id);
|
||||
task.info.decl_id, task.info.callee_id,
|
||||
task.info.override_self_type_id);
|
||||
|
||||
context.scope_stack().Pop();
|
||||
}
|
||||
|
||||
auto BuildThunk(Context& context, SemIR::FunctionId signature_id,
|
||||
SemIR::SpecificId signature_specific_id,
|
||||
SemIR::TypeId signature_self_type_override_id,
|
||||
SemIR::InstId callee_id, bool defer_definition)
|
||||
-> SemIR::InstId {
|
||||
SemIR::TypeId override_self_type_id, SemIR::InstId callee_id,
|
||||
bool defer_definition) -> SemIR::InstId {
|
||||
auto callee = SemIR::GetCalleeAsFunction(context.sem_ir(), callee_id);
|
||||
|
||||
// Check whether we can use the given function without a thunk.
|
||||
@@ -473,8 +475,7 @@ auto BuildThunk(Context& context, SemIR::FunctionId signature_id,
|
||||
CheckFunctionTypeMatches(
|
||||
context, context.functions().Get(callee.function_id),
|
||||
context.functions().Get(signature_id), signature_specific_id,
|
||||
/*check_syntax=*/false, signature_self_type_override_id,
|
||||
/*diagnose=*/false)) {
|
||||
/*check_syntax=*/false, /*diagnose=*/false)) {
|
||||
return callee_id;
|
||||
}
|
||||
|
||||
@@ -504,14 +505,15 @@ auto BuildThunk(Context& context, SemIR::FunctionId signature_id,
|
||||
// We can't use the function directly. Build a thunk.
|
||||
// TODO: Check for and diagnose obvious reasons why this will fail, such as
|
||||
// arity mismatch, before trying to build the thunk.
|
||||
auto [function_id, thunk_inst_id] = CloneFunctionDecl(
|
||||
context, SemIR::LocId(callee_id), signature_id, signature_specific_id,
|
||||
signature_self_type_override_id, callee.function_id);
|
||||
auto [function_id, thunk_inst_id] =
|
||||
CloneFunctionDecl(context, SemIR::LocId(callee_id), signature_id,
|
||||
signature_specific_id, callee.function_id);
|
||||
|
||||
auto thunk_id =
|
||||
context.sem_ir().thunks().Add({.callee_id = callee_id,
|
||||
.signature_id = signature_id,
|
||||
.specific_id = signature_specific_id});
|
||||
auto thunk_id = context.sem_ir().thunks().Add(
|
||||
{.callee_id = callee_id,
|
||||
.signature_id = signature_id,
|
||||
.specific_id = signature_specific_id,
|
||||
.override_self_type_id = override_self_type_id});
|
||||
|
||||
// Track that this function is a thunk.
|
||||
context.functions().Get(function_id).SetThunk(thunk_id);
|
||||
@@ -526,10 +528,11 @@ auto BuildThunk(Context& context, SemIR::FunctionId signature_id,
|
||||
.function_id = function_id,
|
||||
.decl_id = thunk_inst_id,
|
||||
.callee_id = callee_id,
|
||||
.override_self_type_id = override_self_type_id,
|
||||
});
|
||||
} else {
|
||||
BuildThunkDefinition(context, signature_id, function_id, thunk_inst_id,
|
||||
callee_id);
|
||||
callee_id, override_self_type_id);
|
||||
context.scope_stack().Pop();
|
||||
}
|
||||
|
||||
|
||||
+13
-10
@@ -12,23 +12,26 @@
|
||||
namespace Carbon::Check {
|
||||
|
||||
// Given a function signature and a callee function, build a thunk that matches
|
||||
// the given signature and calls the specified callee. Returns the callee
|
||||
// unchanged if it can be used directly.
|
||||
// the given signature and calls the specified callee. If
|
||||
// `override_self_type_id` is not `None`, this thunk wraps a virtual function
|
||||
// override declared in the given type. Returns the callee unchanged if it can
|
||||
// be used directly.
|
||||
auto BuildThunk(Context& context, SemIR::FunctionId signature_id,
|
||||
SemIR::SpecificId signature_specific_id,
|
||||
SemIR::TypeId signature_self_type_override_id,
|
||||
SemIR::InstId callee_id, bool defer_definition)
|
||||
-> SemIR::InstId;
|
||||
SemIR::TypeId override_self_type_id, SemIR::InstId callee_id,
|
||||
bool defer_definition) -> SemIR::InstId;
|
||||
|
||||
// Builds a call to a function that forwards a call argument list built for
|
||||
// `function_id` to a call to `callee_id`, for use when building a call from a
|
||||
// thunk to its target. This is like `PerformCall`, except that it takes a list
|
||||
// of call arguments for `function_id`, not a syntactic argument list.
|
||||
// Builds a call to a function that forwards a call argument list `call_arg_ids`
|
||||
// built for `function_id` to a call to `callee_id`, for use when building a
|
||||
// call from a thunk to its target. `param_pattern_ids` contains the parameter
|
||||
// patterns of `function_id`. If `override_self_type_id` is not `None`,
|
||||
// `callee_id` refers to a virtual function override declared in the given type.
|
||||
auto PerformThunkCall(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::FunctionId function_id,
|
||||
llvm::ArrayRef<SemIR::InstId> param_pattern_ids,
|
||||
llvm::ArrayRef<SemIR::InstId> call_arg_ids,
|
||||
SemIR::InstId callee_id) -> SemIR::InstId;
|
||||
SemIR::InstId callee_id,
|
||||
SemIR::TypeId override_self_type_id) -> SemIR::InstId;
|
||||
|
||||
// Builds the definition for a thunk whose definition was deferred until the end
|
||||
// of the enclosing scope.
|
||||
|
||||
@@ -124,6 +124,28 @@ auto GetAggregateElement(FunctionContext& context, SemIR::InstId aggr_inst_id,
|
||||
}
|
||||
}
|
||||
|
||||
auto GetEnclosingAggregate(FunctionContext& context,
|
||||
FunctionContext::TypeInFile aggr_type,
|
||||
SemIR::InstId element_id, SemIR::ElementIndex index)
|
||||
-> llvm::Value* {
|
||||
auto object_repr = FunctionContext::TypeInFile{
|
||||
.file = aggr_type.file,
|
||||
.type_id = aggr_type.file->types().GetObjectRepr(aggr_type.type_id)};
|
||||
auto* llvm_object_type =
|
||||
llvm::cast<llvm::StructType>(context.GetType(object_repr));
|
||||
const auto* object_layout =
|
||||
context.llvm_module().getDataLayout().getStructLayout(llvm_object_type);
|
||||
llvm::APInt offset(
|
||||
64, object_layout->getElementOffset(GetElementIndex(object_repr, index)),
|
||||
/*isSigned=*/true);
|
||||
|
||||
auto* element_addr = context.GetValue(element_id);
|
||||
if (offset == 0) {
|
||||
return element_addr;
|
||||
}
|
||||
CARBON_FATAL("TODO: emit a getelementptr with a negative offset");
|
||||
}
|
||||
|
||||
auto EmitAggregateValueRepr(FunctionContext& context,
|
||||
SemIR::InstId value_inst_id,
|
||||
SemIR::InstBlockId refs_id) -> llvm::Value* {
|
||||
|
||||
@@ -31,6 +31,13 @@ auto EmitAggregateInitializer(FunctionContext& context,
|
||||
SemIR::InstBlockId refs_id, llvm::Twine name)
|
||||
-> llvm::Value*;
|
||||
|
||||
// Given that `element_id` is the `index` element of an aggregate of type
|
||||
// `aggr_type`, returns a reference to that aggregate.
|
||||
auto GetEnclosingAggregate(FunctionContext& context,
|
||||
FunctionContext::TypeInFile aggr_type,
|
||||
SemIR::InstId element_id, SemIR::ElementIndex index)
|
||||
-> llvm::Value*;
|
||||
|
||||
} // namespace Carbon::Lower
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_LOWER_AGGREGATE_H_
|
||||
|
||||
@@ -583,6 +583,8 @@ auto FileContext::BuildFunctionBody(SemIR::FunctionId function_id,
|
||||
// Otherwise, always inline thunks.
|
||||
if (definition_function.special_function_kind ==
|
||||
SemIR::Function::SpecialFunctionKind::Thunk) {
|
||||
// TODO: emit the thunk as an alias instead of a separate function,
|
||||
// when that would be correct.
|
||||
attr_builder.addAttribute(llvm::Attribute::AlwaysInline);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,13 @@ auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
|
||||
GetStructFieldName(object_repr, inst.index)));
|
||||
}
|
||||
|
||||
auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
|
||||
SemIR::EnclosingClassAccess inst) -> void {
|
||||
auto aggr_type = context.GetTypeIdOfInst(inst_id);
|
||||
context.SetLocal(inst_id, GetEnclosingAggregate(context, aggr_type,
|
||||
inst.element_id, inst.index));
|
||||
}
|
||||
|
||||
auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
|
||||
SemIR::ClassInit inst) -> void {
|
||||
context.SetLocal(inst_id,
|
||||
|
||||
+80
-56
@@ -216,7 +216,7 @@ fn Use() {
|
||||
// CHECK:STDOUT: source_filename = "classes.carbon"
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: @"_CIntermediate.Classes.$vtable" = unnamed_addr constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @_CFn.Intermediate.Classes to i64), i64 ptrtoint (ptr @"_CIntermediate.Classes.$vtable" to i64)) to i32)]
|
||||
// CHECK:STDOUT: @"_CDerived.Classes.$vtable" = unnamed_addr constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @_CFn.Derived.Classes to i64), i64 ptrtoint (ptr @"_CDerived.Classes.$vtable" to i64)) to i32)]
|
||||
// CHECK:STDOUT: @"_CDerived.Classes.$vtable" = unnamed_addr constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @"_CFn:thunk:Intermediate.Classes:Derived.Classes" to i64), i64 ptrtoint (ptr @"_CDerived.Classes.$vtable" to i64)) to i32)]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_CFn.Intermediate.Classes(ptr %self) #0 !dbg !4 {
|
||||
@@ -230,7 +230,15 @@ fn Use() {
|
||||
// CHECK:STDOUT: ret void, !dbg !14
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
|
||||
// CHECK:STDOUT: define void @"_CFn:thunk:Intermediate.Classes:Derived.Classes"(ptr %self) #1 !dbg !15 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @_CFn.Derived.Classes(ptr %self), !dbg !18
|
||||
// CHECK:STDOUT: ret void, !dbg !18
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: attributes #0 = { nounwind }
|
||||
// CHECK:STDOUT: attributes #1 = { alwaysinline nounwind }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !llvm.module.flags = !{!0, !1}
|
||||
// CHECK:STDOUT: !llvm.dbg.cu = !{!2}
|
||||
@@ -250,6 +258,10 @@ fn Use() {
|
||||
// CHECK:STDOUT: !12 = !{!13}
|
||||
// CHECK:STDOUT: !13 = !DILocalVariable(arg: 1, scope: !11, type: !7)
|
||||
// CHECK:STDOUT: !14 = !DILocation(line: 14, column: 3, scope: !11)
|
||||
// CHECK:STDOUT: !15 = distinct !DISubprogram(name: "Fn", linkageName: "_CFn:thunk:Intermediate.Classes:Derived.Classes", scope: null, file: !3, line: 14, type: !5, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !16)
|
||||
// CHECK:STDOUT: !16 = !{!17}
|
||||
// CHECK:STDOUT: !17 = !DILocalVariable(arg: 1, scope: !15, type: !7)
|
||||
// CHECK:STDOUT: !18 = !DILocation(line: 14, column: 3, scope: !15)
|
||||
// CHECK:STDOUT: ; ModuleID = 'create.carbon'
|
||||
// CHECK:STDOUT: source_filename = "create.carbon"
|
||||
// CHECK:STDOUT:
|
||||
@@ -290,7 +302,7 @@ fn Use() {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: declare void @_CFn.Intermediate.Classes(ptr)
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: declare void @_CFn.Derived.Classes(ptr)
|
||||
// CHECK:STDOUT: declare void @"_CFn:thunk:Intermediate.Classes:Derived.Classes"(ptr)
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.599adb417fbfaec7:core.Destroy.Core"(ptr %self) #0 !dbg !15 {
|
||||
@@ -448,7 +460,7 @@ fn Use() {
|
||||
// CHECK:STDOUT: ret void, !dbg !22
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: declare void @_CFn.Derived.Classes(ptr)
|
||||
// CHECK:STDOUT: declare void @"_CFn:thunk:Intermediate.Classes:Derived.Classes"(ptr)
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_CMakeDerivedFromNonPartial.Main(ptr sret({ { ptr, {} } }) %return) #0 !dbg !23 {
|
||||
@@ -737,68 +749,76 @@ fn Use() {
|
||||
// CHECK:STDOUT: source_filename = "call_impl.carbon"
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: @"_CBase.Main.$vtable" = unnamed_addr constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @_CF.Base.Main to i64), i64 ptrtoint (ptr @"_CBase.Main.$vtable" to i64)) to i32)]
|
||||
// CHECK:STDOUT: @"_CDerived.Main.$vtable" = unnamed_addr constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @_CF.Derived.Main to i64), i64 ptrtoint (ptr @"_CDerived.Main.$vtable" to i64)) to i32)]
|
||||
// CHECK:STDOUT: @"_CDerived.Main.$vtable" = unnamed_addr constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @"_CF:thunk:Base.Main:Derived.Main" to i64), i64 ptrtoint (ptr @"_CDerived.Main.$vtable" to i64)) to i32)]
|
||||
// CHECK:STDOUT: @Derived.val.loc14_32.5 = internal constant { { ptr } } poison
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: declare void @_CF.Base.Main(ptr)
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: declare void @_CF.Derived.Main(ptr)
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_CUse.Main() #0 !dbg !4 {
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
|
||||
// CHECK:STDOUT: define void @"_CF:thunk:Base.Main:Derived.Main"(ptr %self) #0 !dbg !4 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %v.var = alloca { { ptr } }, align 8, !dbg !7
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %v.var), !dbg !7
|
||||
// CHECK:STDOUT: %.loc14_32.2.base = getelementptr inbounds nuw { { ptr } }, ptr %v.var, i32 0, i32 0, !dbg !8
|
||||
// CHECK:STDOUT: %.loc14_31.2.vptr = getelementptr inbounds nuw { ptr }, ptr %.loc14_32.2.base, i32 0, i32 0, !dbg !9
|
||||
// CHECK:STDOUT: %.loc14_32.6.base = getelementptr inbounds nuw { { ptr } }, ptr %v.var, i32 0, i32 0, !dbg !8
|
||||
// CHECK:STDOUT: %.loc14_32.7.vptr = getelementptr inbounds nuw { ptr }, ptr %.loc14_32.6.base, i32 0, i32 0, !dbg !8
|
||||
// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %v.var, ptr align 8 @Derived.val.loc14_32.5, i64 8, i1 false), !dbg !8
|
||||
// CHECK:STDOUT: store ptr @"_CDerived.Main.$vtable", ptr %.loc14_32.7.vptr, align 8, !dbg !8
|
||||
// CHECK:STDOUT: %.loc15_3.1.base = getelementptr inbounds nuw { { ptr } }, ptr %v.var, i32 0, i32 0, !dbg !10
|
||||
// CHECK:STDOUT: %Base.F.call.vtable = load ptr, ptr %.loc15_3.1.base, align 8, !dbg !10
|
||||
// CHECK:STDOUT: %Base.F.call = call ptr @llvm.load.relative.i32(ptr %Base.F.call.vtable, i32 0), !dbg !10
|
||||
// CHECK:STDOUT: call void %Base.F.call(ptr %.loc15_3.1.base), !dbg !10
|
||||
// CHECK:STDOUT: call void @"_COp.8185e3504351afa8:core.Destroy.Core"(ptr %v.var), !dbg !7
|
||||
// CHECK:STDOUT: ret void, !dbg !11
|
||||
// CHECK:STDOUT: call void @_CF.Derived.Main(ptr %self), !dbg !10
|
||||
// CHECK:STDOUT: ret void, !dbg !10
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.a8f528cd70a29ff8:core.Destroy.Core"(ptr %self) #0 !dbg !12 {
|
||||
// CHECK:STDOUT: define void @_CUse.Main() #1 !dbg !11 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %v.var = alloca { { ptr } }, align 8, !dbg !14
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %v.var), !dbg !14
|
||||
// CHECK:STDOUT: %.loc14_32.2.base = getelementptr inbounds nuw { { ptr } }, ptr %v.var, i32 0, i32 0, !dbg !15
|
||||
// CHECK:STDOUT: %.loc14_31.2.vptr = getelementptr inbounds nuw { ptr }, ptr %.loc14_32.2.base, i32 0, i32 0, !dbg !16
|
||||
// CHECK:STDOUT: %.loc14_32.6.base = getelementptr inbounds nuw { { ptr } }, ptr %v.var, i32 0, i32 0, !dbg !15
|
||||
// CHECK:STDOUT: %.loc14_32.7.vptr = getelementptr inbounds nuw { ptr }, ptr %.loc14_32.6.base, i32 0, i32 0, !dbg !15
|
||||
// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %v.var, ptr align 8 @Derived.val.loc14_32.5, i64 8, i1 false), !dbg !15
|
||||
// CHECK:STDOUT: store ptr @"_CDerived.Main.$vtable", ptr %.loc14_32.7.vptr, align 8, !dbg !15
|
||||
// CHECK:STDOUT: %.loc15_3.1.base = getelementptr inbounds nuw { { ptr } }, ptr %v.var, i32 0, i32 0, !dbg !17
|
||||
// CHECK:STDOUT: %Base.F.call.vtable = load ptr, ptr %.loc15_3.1.base, align 8, !dbg !17
|
||||
// CHECK:STDOUT: %Base.F.call = call ptr @llvm.load.relative.i32(ptr %Base.F.call.vtable, i32 0), !dbg !17
|
||||
// CHECK:STDOUT: call void %Base.F.call(ptr %.loc15_3.1.base), !dbg !17
|
||||
// CHECK:STDOUT: call void @"_COp.8185e3504351afa8:core.Destroy.Core"(ptr %v.var), !dbg !14
|
||||
// CHECK:STDOUT: ret void, !dbg !18
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.a45b619846c20518:core.Destroy.Core"(ptr %self) #0 !dbg !19 {
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.a8f528cd70a29ff8:core.Destroy.Core"(ptr %self) #1 !dbg !19 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !22
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.4e1364ec5889efef:core.Destroy.Core"(ptr %self) #0 !dbg !23 {
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.a45b619846c20518:core.Destroy.Core"(ptr %self) #1 !dbg !23 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !26
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.8185e3504351afa8:core.Destroy.Core"(ptr %self) #0 !dbg !27 {
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.4e1364ec5889efef:core.Destroy.Core"(ptr %self) #1 !dbg !27 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !30
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
|
||||
// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #1
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.8185e3504351afa8:core.Destroy.Core"(ptr %self) #1 !dbg !31 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !34
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
|
||||
// CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i64, i1 immarg) #1
|
||||
// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #2
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
|
||||
// CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i64, i1 immarg) #2
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: read)
|
||||
// CHECK:STDOUT: declare ptr @llvm.load.relative.i32(ptr, i32) #2
|
||||
// CHECK:STDOUT: declare ptr @llvm.load.relative.i32(ptr, i32) #3
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: attributes #0 = { nounwind }
|
||||
// CHECK:STDOUT: attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||
// CHECK:STDOUT: attributes #2 = { nocallback nofree nosync nounwind willreturn memory(argmem: read) }
|
||||
// CHECK:STDOUT: attributes #0 = { alwaysinline nounwind }
|
||||
// CHECK:STDOUT: attributes #1 = { nounwind }
|
||||
// CHECK:STDOUT: attributes #2 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||
// CHECK:STDOUT: attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: read) }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !llvm.module.flags = !{!0, !1}
|
||||
// CHECK:STDOUT: !llvm.dbg.cu = !{!2}
|
||||
@@ -807,33 +827,37 @@ fn Use() {
|
||||
// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
// CHECK:STDOUT: !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
|
||||
// CHECK:STDOUT: !3 = !DIFile(filename: "call_impl.carbon", directory: "")
|
||||
// CHECK:STDOUT: !4 = distinct !DISubprogram(name: "Use", linkageName: "_CUse.Main", scope: null, file: !3, line: 13, type: !5, spFlags: DISPFlagDefinition, unit: !2)
|
||||
// CHECK:STDOUT: !4 = distinct !DISubprogram(name: "F", linkageName: "_CF:thunk:Base.Main:Derived.Main", scope: null, file: !3, line: 10, type: !5, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !8)
|
||||
// CHECK:STDOUT: !5 = !DISubroutineType(types: !6)
|
||||
// CHECK:STDOUT: !6 = !{null}
|
||||
// CHECK:STDOUT: !7 = !DILocation(line: 14, column: 3, scope: !4)
|
||||
// CHECK:STDOUT: !8 = !DILocation(line: 14, column: 21, scope: !4)
|
||||
// CHECK:STDOUT: !9 = !DILocation(line: 14, column: 30, scope: !4)
|
||||
// CHECK:STDOUT: !10 = !DILocation(line: 15, column: 3, scope: !4)
|
||||
// CHECK:STDOUT: !11 = !DILocation(line: 13, column: 1, scope: !4)
|
||||
// CHECK:STDOUT: !12 = distinct !DISubprogram(name: "Op", linkageName: "_COp.a8f528cd70a29ff8:core.Destroy.Core", scope: null, file: !3, line: 14, type: !13, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !16)
|
||||
// CHECK:STDOUT: !13 = !DISubroutineType(types: !14)
|
||||
// CHECK:STDOUT: !14 = !{null, !15}
|
||||
// CHECK:STDOUT: !15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
|
||||
// CHECK:STDOUT: !16 = !{!17}
|
||||
// CHECK:STDOUT: !17 = !DILocalVariable(arg: 1, scope: !12, type: !15)
|
||||
// CHECK:STDOUT: !18 = !DILocation(line: 14, column: 3, scope: !12)
|
||||
// CHECK:STDOUT: !19 = distinct !DISubprogram(name: "Op", linkageName: "_COp.a45b619846c20518:core.Destroy.Core", scope: null, file: !3, line: 14, type: !13, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !20)
|
||||
// CHECK:STDOUT: !6 = !{null, !7}
|
||||
// CHECK:STDOUT: !7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
|
||||
// CHECK:STDOUT: !8 = !{!9}
|
||||
// CHECK:STDOUT: !9 = !DILocalVariable(arg: 1, scope: !4, type: !7)
|
||||
// CHECK:STDOUT: !10 = !DILocation(line: 10, column: 3, scope: !4)
|
||||
// CHECK:STDOUT: !11 = distinct !DISubprogram(name: "Use", linkageName: "_CUse.Main", scope: null, file: !3, line: 13, type: !12, spFlags: DISPFlagDefinition, unit: !2)
|
||||
// CHECK:STDOUT: !12 = !DISubroutineType(types: !13)
|
||||
// CHECK:STDOUT: !13 = !{null}
|
||||
// CHECK:STDOUT: !14 = !DILocation(line: 14, column: 3, scope: !11)
|
||||
// CHECK:STDOUT: !15 = !DILocation(line: 14, column: 21, scope: !11)
|
||||
// CHECK:STDOUT: !16 = !DILocation(line: 14, column: 30, scope: !11)
|
||||
// CHECK:STDOUT: !17 = !DILocation(line: 15, column: 3, scope: !11)
|
||||
// CHECK:STDOUT: !18 = !DILocation(line: 13, column: 1, scope: !11)
|
||||
// CHECK:STDOUT: !19 = distinct !DISubprogram(name: "Op", linkageName: "_COp.a8f528cd70a29ff8:core.Destroy.Core", scope: null, file: !3, line: 14, type: !5, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !20)
|
||||
// CHECK:STDOUT: !20 = !{!21}
|
||||
// CHECK:STDOUT: !21 = !DILocalVariable(arg: 1, scope: !19, type: !15)
|
||||
// CHECK:STDOUT: !21 = !DILocalVariable(arg: 1, scope: !19, type: !7)
|
||||
// CHECK:STDOUT: !22 = !DILocation(line: 14, column: 3, scope: !19)
|
||||
// CHECK:STDOUT: !23 = distinct !DISubprogram(name: "Op", linkageName: "_COp.4e1364ec5889efef:core.Destroy.Core", scope: null, file: !3, line: 14, type: !13, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !24)
|
||||
// CHECK:STDOUT: !23 = distinct !DISubprogram(name: "Op", linkageName: "_COp.a45b619846c20518:core.Destroy.Core", scope: null, file: !3, line: 14, type: !5, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !24)
|
||||
// CHECK:STDOUT: !24 = !{!25}
|
||||
// CHECK:STDOUT: !25 = !DILocalVariable(arg: 1, scope: !23, type: !15)
|
||||
// CHECK:STDOUT: !25 = !DILocalVariable(arg: 1, scope: !23, type: !7)
|
||||
// CHECK:STDOUT: !26 = !DILocation(line: 14, column: 3, scope: !23)
|
||||
// CHECK:STDOUT: !27 = distinct !DISubprogram(name: "Op", linkageName: "_COp.8185e3504351afa8:core.Destroy.Core", scope: null, file: !3, line: 14, type: !13, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !28)
|
||||
// CHECK:STDOUT: !27 = distinct !DISubprogram(name: "Op", linkageName: "_COp.4e1364ec5889efef:core.Destroy.Core", scope: null, file: !3, line: 14, type: !5, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !28)
|
||||
// CHECK:STDOUT: !28 = !{!29}
|
||||
// CHECK:STDOUT: !29 = !DILocalVariable(arg: 1, scope: !27, type: !15)
|
||||
// CHECK:STDOUT: !29 = !DILocalVariable(arg: 1, scope: !27, type: !7)
|
||||
// CHECK:STDOUT: !30 = !DILocation(line: 14, column: 3, scope: !27)
|
||||
// CHECK:STDOUT: !31 = distinct !DISubprogram(name: "Op", linkageName: "_COp.8185e3504351afa8:core.Destroy.Core", scope: null, file: !3, line: 14, type: !5, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !32)
|
||||
// CHECK:STDOUT: !32 = !{!33}
|
||||
// CHECK:STDOUT: !33 = !DILocalVariable(arg: 1, scope: !31, type: !7)
|
||||
// CHECK:STDOUT: !34 = !DILocation(line: 14, column: 3, scope: !31)
|
||||
// CHECK:STDOUT: ; ModuleID = 'generic_noop.carbon'
|
||||
// CHECK:STDOUT: source_filename = "generic_noop.carbon"
|
||||
// CHECK:STDOUT:
|
||||
@@ -1095,14 +1119,14 @@ fn Use() {
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
|
||||
// CHECK:STDOUT: define void @"_CF:thunk:Base.Main:Derived.Main"(ptr sret({}) %return, ptr %self, ptr %n) #1 !dbg !12 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %.loc17_58.1.temp = alloca {}, align 1, !dbg !16
|
||||
// CHECK:STDOUT: %.loc17_58.2.temp = alloca {}, align 1, !dbg !16
|
||||
// CHECK:STDOUT: %.loc12_33.1.temp = alloca {}, align 1, !dbg !17
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc17_58.1.temp), !dbg !16
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc17_58.2.temp), !dbg !16
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc12_33.1.temp), !dbg !17
|
||||
// CHECK:STDOUT: call void @"_CConvert.From.Main:ImplicitAs.a3bb440f6426a7d6.Core"(ptr %.loc12_33.1.temp, ptr %n), !dbg !17
|
||||
// CHECK:STDOUT: call void @_CF.Derived.Main(ptr %.loc17_58.1.temp, ptr %self, ptr %.loc12_33.1.temp), !dbg !16
|
||||
// CHECK:STDOUT: call void @"_CConvert.From.Main:ImplicitAs.a3bb440f6426a7d6.Core"(ptr %return, ptr %.loc17_58.1.temp), !dbg !16
|
||||
// CHECK:STDOUT: call void @"_COp.419398171642b7b7:core.Destroy.Core"(ptr %.loc17_58.1.temp), !dbg !16
|
||||
// CHECK:STDOUT: call void @_CF.Derived.Main(ptr %.loc17_58.2.temp, ptr %self, ptr %.loc12_33.1.temp), !dbg !16
|
||||
// CHECK:STDOUT: call void @"_CConvert.From.Main:ImplicitAs.a3bb440f6426a7d6.Core"(ptr %return, ptr %.loc17_58.2.temp), !dbg !16
|
||||
// CHECK:STDOUT: call void @"_COp.419398171642b7b7:core.Destroy.Core"(ptr %.loc17_58.2.temp), !dbg !16
|
||||
// CHECK:STDOUT: call void @"_COp.41ca6508118965ec:core.Destroy.Core"(ptr %.loc12_33.1.temp), !dbg !17
|
||||
// CHECK:STDOUT: ret void, !dbg !16
|
||||
// CHECK:STDOUT: }
|
||||
|
||||
@@ -164,42 +164,47 @@ auto DoThing() -> void {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
|
||||
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.Derived.Main"(ptr %self) #6 !dbg !29 {
|
||||
// CHECK:STDOUT: define void @"_Cfunc:thunk:Base.Cpp:Derived.Main"(ptr %self) #6 !dbg !29 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @"_COp.8185e3504351afa8:core.Destroy.Core"(ptr %self), !dbg !32
|
||||
// CHECK:STDOUT: call void @_Cfunc.Derived.Main(ptr %self), !dbg !32
|
||||
// CHECK:STDOUT: ret void, !dbg !32
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.13b019890e86b6be:core.Destroy.Core"(ptr %self) #5 !dbg !33 {
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
|
||||
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.Derived.Main"(ptr %self) #6 !dbg !33 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @"_COp.8185e3504351afa8:core.Destroy.Core"(ptr %self), !dbg !36
|
||||
// CHECK:STDOUT: ret void, !dbg !36
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.8185e3504351afa8:core.Destroy.Core"(ptr %self) #5 !dbg !37 {
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.13b019890e86b6be:core.Destroy.Core"(ptr %self) #5 !dbg !37 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !40
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_Cfunc__carbon_thunk.Derived.Main(ptr %self) #5 !dbg !41 {
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.8185e3504351afa8:core.Destroy.Core"(ptr %self) #5 !dbg !41 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %Derived.func.call.vtable = load ptr, ptr %self, align 8, !dbg !44
|
||||
// CHECK:STDOUT: %Derived.func.call = call ptr @llvm.load.relative.i32(ptr %Derived.func.call.vtable, i32 4), !dbg !44
|
||||
// CHECK:STDOUT: call void %Derived.func.call(ptr %self), !dbg !44
|
||||
// CHECK:STDOUT: ret void, !dbg !44
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_Cother_func__carbon_thunk.Derived.Main(ptr %self) #5 !dbg !45 {
|
||||
// CHECK:STDOUT: define void @_Cfunc__carbon_thunk.Derived.Main(ptr %self) #5 !dbg !45 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %Derived.other_func.call.vtable = load ptr, ptr %self, align 8, !dbg !48
|
||||
// CHECK:STDOUT: %Derived.other_func.call = call ptr @llvm.load.relative.i32(ptr %Derived.other_func.call.vtable, i32 8), !dbg !48
|
||||
// CHECK:STDOUT: call void %Derived.other_func.call(ptr %self), !dbg !48
|
||||
// CHECK:STDOUT: call void @_Cfunc.Derived.Main(ptr %self), !dbg !48
|
||||
// CHECK:STDOUT: ret void, !dbg !48
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_Cother_func__carbon_thunk.Derived.Main(ptr %self) #5 !dbg !49 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %Derived.other_func.call.vtable = load ptr, ptr %self, align 8, !dbg !52
|
||||
// CHECK:STDOUT: %Derived.other_func.call = call ptr @llvm.load.relative.i32(ptr %Derived.other_func.call.vtable, i32 8), !dbg !52
|
||||
// CHECK:STDOUT: call void %Derived.other_func.call(ptr %self), !dbg !52
|
||||
// CHECK:STDOUT: ret void, !dbg !52
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: read)
|
||||
// CHECK:STDOUT: declare ptr @llvm.load.relative.i32(ptr, i32) #7
|
||||
// CHECK:STDOUT:
|
||||
@@ -238,7 +243,7 @@ auto DoThing() -> void {
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN11FurtherBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %this) unnamed_addr #3 comdat align 2 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %this.addr = alloca ptr, align 8
|
||||
// CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !49
|
||||
// CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !53
|
||||
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
|
||||
// CHECK:STDOUT: store ptr getelementptr inbounds inrange(-16, 8) ({ [3 x ptr] }, ptr @_ZTV11FurtherBase, i32 0, i32 0, i32 2), ptr %this1, align 8, !tbaa !16
|
||||
// CHECK:STDOUT: ret void
|
||||
@@ -248,7 +253,6 @@ auto DoThing() -> void {
|
||||
// CHECK:STDOUT: uselistorder ptr @_ZN6Carbon7DerivedC2Ev, { 1, 0 }
|
||||
// CHECK:STDOUT: uselistorder ptr @_ZN6Carbon7DerivedD2Ev, { 1, 0 }
|
||||
// CHECK:STDOUT: uselistorder ptr @_ZN11FurtherBase17further_base_funcEv, { 2, 1, 0 }
|
||||
// CHECK:STDOUT: uselistorder ptr @llvm.load.relative.i32, { 1, 0 }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: attributes #0 = { mustprogress noinline nounwind optnone uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
|
||||
// CHECK:STDOUT: attributes #1 = { mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
|
||||
@@ -293,25 +297,29 @@ auto DoThing() -> void {
|
||||
// CHECK:STDOUT: !26 = !{!27}
|
||||
// CHECK:STDOUT: !27 = !DILocalVariable(arg: 1, scope: !25, type: !21)
|
||||
// CHECK:STDOUT: !28 = !DILocation(line: 26, column: 3, scope: !25)
|
||||
// CHECK:STDOUT: !29 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.Derived.Main", scope: null, file: !6, line: 22, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !30)
|
||||
// CHECK:STDOUT: !29 = distinct !DISubprogram(name: "func", linkageName: "_Cfunc:thunk:Base.Cpp:Derived.Main", scope: null, file: !6, line: 26, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !30)
|
||||
// CHECK:STDOUT: !30 = !{!31}
|
||||
// CHECK:STDOUT: !31 = !DILocalVariable(arg: 1, scope: !29, type: !21)
|
||||
// CHECK:STDOUT: !32 = !DILocation(line: 22, column: 1, scope: !29)
|
||||
// CHECK:STDOUT: !33 = distinct !DISubprogram(name: "Op", linkageName: "_COp.13b019890e86b6be:core.Destroy.Core", scope: null, file: !6, line: 22, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !34)
|
||||
// CHECK:STDOUT: !32 = !DILocation(line: 26, column: 3, scope: !29)
|
||||
// CHECK:STDOUT: !33 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.Derived.Main", scope: null, file: !6, line: 22, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !34)
|
||||
// CHECK:STDOUT: !34 = !{!35}
|
||||
// CHECK:STDOUT: !35 = !DILocalVariable(arg: 1, scope: !33, type: !21)
|
||||
// CHECK:STDOUT: !36 = !DILocation(line: 22, column: 1, scope: !33)
|
||||
// CHECK:STDOUT: !37 = distinct !DISubprogram(name: "Op", linkageName: "_COp.8185e3504351afa8:core.Destroy.Core", scope: null, file: !6, line: 22, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !38)
|
||||
// CHECK:STDOUT: !37 = distinct !DISubprogram(name: "Op", linkageName: "_COp.13b019890e86b6be:core.Destroy.Core", scope: null, file: !6, line: 22, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !38)
|
||||
// CHECK:STDOUT: !38 = !{!39}
|
||||
// CHECK:STDOUT: !39 = !DILocalVariable(arg: 1, scope: !37, type: !21)
|
||||
// CHECK:STDOUT: !40 = !DILocation(line: 22, column: 1, scope: !37)
|
||||
// CHECK:STDOUT: !41 = distinct !DISubprogram(name: "func__carbon_thunk", linkageName: "_Cfunc__carbon_thunk.Derived.Main", scope: null, file: !6, line: 26, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !42)
|
||||
// CHECK:STDOUT: !41 = distinct !DISubprogram(name: "Op", linkageName: "_COp.8185e3504351afa8:core.Destroy.Core", scope: null, file: !6, line: 22, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !42)
|
||||
// CHECK:STDOUT: !42 = !{!43}
|
||||
// CHECK:STDOUT: !43 = !DILocalVariable(arg: 1, scope: !41, type: !21)
|
||||
// CHECK:STDOUT: !44 = !DILocation(line: 26, column: 3, scope: !41)
|
||||
// CHECK:STDOUT: !45 = distinct !DISubprogram(name: "other_func__carbon_thunk", linkageName: "_Cother_func__carbon_thunk.Derived.Main", scope: null, file: !6, line: 24, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !46)
|
||||
// CHECK:STDOUT: !44 = !DILocation(line: 22, column: 1, scope: !41)
|
||||
// CHECK:STDOUT: !45 = distinct !DISubprogram(name: "func__carbon_thunk", linkageName: "_Cfunc__carbon_thunk.Derived.Main", scope: null, file: !6, line: 26, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !46)
|
||||
// CHECK:STDOUT: !46 = !{!47}
|
||||
// CHECK:STDOUT: !47 = !DILocalVariable(arg: 1, scope: !45, type: !21)
|
||||
// CHECK:STDOUT: !48 = !DILocation(line: 24, column: 3, scope: !45)
|
||||
// CHECK:STDOUT: !49 = !{!50, !50, i64 0}
|
||||
// CHECK:STDOUT: !50 = !{!"p1 _ZTS11FurtherBase", !13, i64 0}
|
||||
// CHECK:STDOUT: !48 = !DILocation(line: 26, column: 3, scope: !45)
|
||||
// CHECK:STDOUT: !49 = distinct !DISubprogram(name: "other_func__carbon_thunk", linkageName: "_Cother_func__carbon_thunk.Derived.Main", scope: null, file: !6, line: 24, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !50)
|
||||
// CHECK:STDOUT: !50 = !{!51}
|
||||
// CHECK:STDOUT: !51 = !DILocalVariable(arg: 1, scope: !49, type: !21)
|
||||
// CHECK:STDOUT: !52 = !DILocation(line: 24, column: 3, scope: !49)
|
||||
// CHECK:STDOUT: !53 = !{!54, !54, i64 0}
|
||||
// CHECK:STDOUT: !54 = !{!"p1 _ZTS11FurtherBase", !13, i64 0}
|
||||
|
||||
+67
-54
@@ -95,7 +95,7 @@ void delete_new_Base() {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %p = alloca ptr, align 8
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %p) #8
|
||||
// CHECK:STDOUT: %call = call noalias noundef nonnull ptr @_Znwm(i64 noundef 8) #11
|
||||
// CHECK:STDOUT: %call = call noalias noundef nonnull ptr @_Znwm(i64 noundef 8) #10
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon5FinalC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %call) #8
|
||||
// CHECK:STDOUT: store ptr %call, ptr %p, align 8, !tbaa !11
|
||||
// CHECK:STDOUT: %0 = load ptr, ptr %p, align 8, !tbaa !11
|
||||
@@ -104,7 +104,7 @@ void delete_new_Base() {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: delete.notnull: ; preds = %entry
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon5FinalD2Ev(ptr noundef nonnull align 8 dead_on_return(8) dereferenceable(8) %0) #8
|
||||
// CHECK:STDOUT: call void @_ZdlPvm(ptr noundef %0, i64 noundef 8) #12
|
||||
// CHECK:STDOUT: call void @_ZdlPvm(ptr noundef %0, i64 noundef 8) #11
|
||||
// CHECK:STDOUT: br label %delete.end
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: delete.end: ; preds = %delete.notnull, %entry
|
||||
@@ -151,7 +151,7 @@ void delete_new_Base() {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %p = alloca ptr, align 8
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %p) #8
|
||||
// CHECK:STDOUT: %call = call noalias noundef nonnull ptr @_Znwm(i64 noundef 8) #11
|
||||
// CHECK:STDOUT: %call = call noalias noundef nonnull ptr @_Znwm(i64 noundef 8) #10
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon4BaseC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %call) #8
|
||||
// CHECK:STDOUT: store ptr %call, ptr %p, align 8, !tbaa !16
|
||||
// CHECK:STDOUT: %0 = load ptr, ptr %p, align 8, !tbaa !16
|
||||
@@ -196,63 +196,70 @@ void delete_new_Base() {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: declare void @_CF.Final.Main(ptr)
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
|
||||
// CHECK:STDOUT: define void @"_CF:thunk:A.Cpp:Final.Main"(ptr %self) #6 !dbg !22 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @_CF.Final.Main(ptr %self), !dbg !28
|
||||
// CHECK:STDOUT: ret void, !dbg !28
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: declare void @_CF.Base.Main(ptr)
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
|
||||
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.Final.Main"(ptr %self) #6 !dbg !22 {
|
||||
// CHECK:STDOUT: define void @"_CF:thunk:A.Cpp:Base.Main"(ptr %self) #6 !dbg !29 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @"_COp.6622c02ec7a967c3:core.Destroy.Core"(ptr %self), !dbg !28
|
||||
// CHECK:STDOUT: ret void, !dbg !28
|
||||
// CHECK:STDOUT: call void @_CF.Base.Main(ptr %self), !dbg !32
|
||||
// CHECK:STDOUT: ret void, !dbg !32
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
|
||||
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.Final.Main"(ptr %self) #6 !dbg !33 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @"_COp.6622c02ec7a967c3:core.Destroy.Core"(ptr %self), !dbg !36
|
||||
// CHECK:STDOUT: ret void, !dbg !36
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: declare void @_ZN1AD1Ev(ptr noundef nonnull align 8 dead_on_return(8) dereferenceable(8)) unnamed_addr #7
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.4fc2347fc019a955:core.Destroy.Core"(ptr %self) #8 !dbg !29 {
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.4fc2347fc019a955:core.Destroy.Core"(ptr %self) #8 !dbg !37 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !32
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.6622c02ec7a967c3:core.Destroy.Core"(ptr %self) #8 !dbg !33 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !36
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_CF__carbon_thunk.Final.Main(ptr %self) #8 !dbg !37 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %Final.F.call.vtable = load ptr, ptr %self, align 8, !dbg !40
|
||||
// CHECK:STDOUT: %Final.F.call = call ptr @llvm.load.relative.i32(ptr %Final.F.call.vtable, i32 8), !dbg !40
|
||||
// CHECK:STDOUT: call void %Final.F.call(ptr %self), !dbg !40
|
||||
// CHECK:STDOUT: ret void, !dbg !40
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
|
||||
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.Base.Main"(ptr %self) #6 !dbg !41 {
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.6622c02ec7a967c3:core.Destroy.Core"(ptr %self) #8 !dbg !41 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @"_COp.a45b619846c20518:core.Destroy.Core"(ptr %self), !dbg !44
|
||||
// CHECK:STDOUT: ret void, !dbg !44
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.a45b619846c20518:core.Destroy.Core"(ptr %self) #8 !dbg !45 {
|
||||
// CHECK:STDOUT: define void @_CF__carbon_thunk.Final.Main(ptr %self) #8 !dbg !45 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @_CF.Final.Main(ptr %self), !dbg !48
|
||||
// CHECK:STDOUT: ret void, !dbg !48
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_CF__carbon_thunk.Base.Main(ptr %self) #8 !dbg !49 {
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
|
||||
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.Base.Main"(ptr %self) #6 !dbg !49 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %Base.F.call.vtable = load ptr, ptr %self, align 8, !dbg !52
|
||||
// CHECK:STDOUT: %Base.F.call = call ptr @llvm.load.relative.i32(ptr %Base.F.call.vtable, i32 8), !dbg !52
|
||||
// CHECK:STDOUT: call void %Base.F.call(ptr %self), !dbg !52
|
||||
// CHECK:STDOUT: call void @"_COp.a45b619846c20518:core.Destroy.Core"(ptr %self), !dbg !52
|
||||
// CHECK:STDOUT: ret void, !dbg !52
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: read)
|
||||
// CHECK:STDOUT: declare ptr @llvm.load.relative.i32(ptr, i32) #9
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.a45b619846c20518:core.Destroy.Core"(ptr %self) #8 !dbg !53 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !56
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_CF__carbon_thunk.Base.Main(ptr %self) #8 !dbg !57 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @_CF.Base.Main(ptr %self), !dbg !60
|
||||
// CHECK:STDOUT: ret void, !dbg !60
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN1AC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %this) unnamed_addr #3 comdat align 2 {
|
||||
@@ -271,11 +278,11 @@ void delete_new_Base() {
|
||||
// CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !11
|
||||
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon5FinalD2Ev(ptr noundef nonnull align 8 dead_on_return(8) dereferenceable(8) %this1) #8
|
||||
// CHECK:STDOUT: call void @_ZdlPvm(ptr noundef %this1, i64 noundef 8) #12
|
||||
// CHECK:STDOUT: call void @_ZdlPvm(ptr noundef %this1, i64 noundef 8) #11
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: declare void @_ZNK1A1FEv(ptr noundef nonnull align 8 dereferenceable(8)) unnamed_addr #10
|
||||
// CHECK:STDOUT: declare void @_ZNK1A1FEv(ptr noundef nonnull align 8 dereferenceable(8)) unnamed_addr #9
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define internal void @_ZN6Carbon5Final1FEv(ptr noundef nonnull align 8 dereferenceable(8) %this) unnamed_addr #5 align 2 {
|
||||
@@ -311,7 +318,7 @@ void delete_new_Base() {
|
||||
// CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !16
|
||||
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon4BaseD2Ev(ptr noundef nonnull align 8 dead_on_return(8) dereferenceable(8) %this1) #8
|
||||
// CHECK:STDOUT: call void @_ZdlPvm(ptr noundef %this1, i64 noundef 8) #12
|
||||
// CHECK:STDOUT: call void @_ZdlPvm(ptr noundef %this1, i64 noundef 8) #11
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
@@ -327,7 +334,6 @@ void delete_new_Base() {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; uselistorder directives
|
||||
// CHECK:STDOUT: uselistorder ptr @_ZN6Carbon5FinalD2Ev, { 2, 1, 0 }
|
||||
// CHECK:STDOUT: uselistorder ptr @llvm.load.relative.i32, { 1, 0 }
|
||||
// CHECK:STDOUT: uselistorder ptr @_ZN1AC2Ev, { 1, 0 }
|
||||
// CHECK:STDOUT: uselistorder ptr @_ZNK1A1FEv, { 2, 1, 0 }
|
||||
// CHECK:STDOUT: uselistorder ptr @__cxa_pure_virtual, { 1, 0 }
|
||||
@@ -342,10 +348,9 @@ void delete_new_Base() {
|
||||
// CHECK:STDOUT: attributes #6 = { alwaysinline nounwind }
|
||||
// CHECK:STDOUT: attributes #7 = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
|
||||
// CHECK:STDOUT: attributes #8 = { nounwind }
|
||||
// CHECK:STDOUT: attributes #9 = { nocallback nofree nosync nounwind willreturn memory(argmem: read) }
|
||||
// CHECK:STDOUT: attributes #10 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
|
||||
// CHECK:STDOUT: attributes #11 = { builtin allocsize(0) }
|
||||
// CHECK:STDOUT: attributes #12 = { builtin nounwind }
|
||||
// CHECK:STDOUT: attributes #9 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
|
||||
// CHECK:STDOUT: attributes #10 = { builtin allocsize(0) }
|
||||
// CHECK:STDOUT: attributes #11 = { builtin nounwind }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4}
|
||||
// CHECK:STDOUT: !llvm.dbg.cu = !{!5}
|
||||
@@ -373,34 +378,42 @@ void delete_new_Base() {
|
||||
// CHECK:STDOUT: !19 = !{!"p1 _ZTS1A", !13, i64 0}
|
||||
// CHECK:STDOUT: !20 = !{}
|
||||
// CHECK:STDOUT: !21 = !{i64 8}
|
||||
// CHECK:STDOUT: !22 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.Final.Main", scope: null, file: !6, line: 12, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !26)
|
||||
// CHECK:STDOUT: !22 = distinct !DISubprogram(name: "F", linkageName: "_CF:thunk:A.Cpp:Final.Main", scope: null, file: !6, line: 14, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !26)
|
||||
// CHECK:STDOUT: !23 = !DISubroutineType(types: !24)
|
||||
// CHECK:STDOUT: !24 = !{null, !25}
|
||||
// CHECK:STDOUT: !25 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
|
||||
// CHECK:STDOUT: !26 = !{!27}
|
||||
// CHECK:STDOUT: !27 = !DILocalVariable(arg: 1, scope: !22, type: !25)
|
||||
// CHECK:STDOUT: !28 = !DILocation(line: 12, column: 1, scope: !22)
|
||||
// CHECK:STDOUT: !29 = distinct !DISubprogram(name: "Op", linkageName: "_COp.4fc2347fc019a955:core.Destroy.Core", scope: null, file: !6, line: 12, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !30)
|
||||
// CHECK:STDOUT: !28 = !DILocation(line: 14, column: 3, scope: !22)
|
||||
// CHECK:STDOUT: !29 = distinct !DISubprogram(name: "F", linkageName: "_CF:thunk:A.Cpp:Base.Main", scope: null, file: !6, line: 19, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !30)
|
||||
// CHECK:STDOUT: !30 = !{!31}
|
||||
// CHECK:STDOUT: !31 = !DILocalVariable(arg: 1, scope: !29, type: !25)
|
||||
// CHECK:STDOUT: !32 = !DILocation(line: 12, column: 1, scope: !29)
|
||||
// CHECK:STDOUT: !33 = distinct !DISubprogram(name: "Op", linkageName: "_COp.6622c02ec7a967c3:core.Destroy.Core", scope: null, file: !6, line: 12, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !34)
|
||||
// CHECK:STDOUT: !32 = !DILocation(line: 19, column: 3, scope: !29)
|
||||
// CHECK:STDOUT: !33 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.Final.Main", scope: null, file: !6, line: 12, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !34)
|
||||
// CHECK:STDOUT: !34 = !{!35}
|
||||
// CHECK:STDOUT: !35 = !DILocalVariable(arg: 1, scope: !33, type: !25)
|
||||
// CHECK:STDOUT: !36 = !DILocation(line: 12, column: 1, scope: !33)
|
||||
// CHECK:STDOUT: !37 = distinct !DISubprogram(name: "F__carbon_thunk", linkageName: "_CF__carbon_thunk.Final.Main", scope: null, file: !6, line: 14, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !38)
|
||||
// CHECK:STDOUT: !37 = distinct !DISubprogram(name: "Op", linkageName: "_COp.4fc2347fc019a955:core.Destroy.Core", scope: null, file: !6, line: 12, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !38)
|
||||
// CHECK:STDOUT: !38 = !{!39}
|
||||
// CHECK:STDOUT: !39 = !DILocalVariable(arg: 1, scope: !37, type: !25)
|
||||
// CHECK:STDOUT: !40 = !DILocation(line: 14, column: 3, scope: !37)
|
||||
// CHECK:STDOUT: !41 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.Base.Main", scope: null, file: !6, line: 17, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !42)
|
||||
// CHECK:STDOUT: !40 = !DILocation(line: 12, column: 1, scope: !37)
|
||||
// CHECK:STDOUT: !41 = distinct !DISubprogram(name: "Op", linkageName: "_COp.6622c02ec7a967c3:core.Destroy.Core", scope: null, file: !6, line: 12, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !42)
|
||||
// CHECK:STDOUT: !42 = !{!43}
|
||||
// CHECK:STDOUT: !43 = !DILocalVariable(arg: 1, scope: !41, type: !25)
|
||||
// CHECK:STDOUT: !44 = !DILocation(line: 17, column: 1, scope: !41)
|
||||
// CHECK:STDOUT: !45 = distinct !DISubprogram(name: "Op", linkageName: "_COp.a45b619846c20518:core.Destroy.Core", scope: null, file: !6, line: 17, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !46)
|
||||
// CHECK:STDOUT: !44 = !DILocation(line: 12, column: 1, scope: !41)
|
||||
// CHECK:STDOUT: !45 = distinct !DISubprogram(name: "F__carbon_thunk", linkageName: "_CF__carbon_thunk.Final.Main", scope: null, file: !6, line: 14, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !46)
|
||||
// CHECK:STDOUT: !46 = !{!47}
|
||||
// CHECK:STDOUT: !47 = !DILocalVariable(arg: 1, scope: !45, type: !25)
|
||||
// CHECK:STDOUT: !48 = !DILocation(line: 17, column: 1, scope: !45)
|
||||
// CHECK:STDOUT: !49 = distinct !DISubprogram(name: "F__carbon_thunk", linkageName: "_CF__carbon_thunk.Base.Main", scope: null, file: !6, line: 19, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !50)
|
||||
// CHECK:STDOUT: !48 = !DILocation(line: 14, column: 3, scope: !45)
|
||||
// CHECK:STDOUT: !49 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.Base.Main", scope: null, file: !6, line: 17, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !50)
|
||||
// CHECK:STDOUT: !50 = !{!51}
|
||||
// CHECK:STDOUT: !51 = !DILocalVariable(arg: 1, scope: !49, type: !25)
|
||||
// CHECK:STDOUT: !52 = !DILocation(line: 19, column: 3, scope: !49)
|
||||
// CHECK:STDOUT: !52 = !DILocation(line: 17, column: 1, scope: !49)
|
||||
// CHECK:STDOUT: !53 = distinct !DISubprogram(name: "Op", linkageName: "_COp.a45b619846c20518:core.Destroy.Core", scope: null, file: !6, line: 17, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !54)
|
||||
// CHECK:STDOUT: !54 = !{!55}
|
||||
// CHECK:STDOUT: !55 = !DILocalVariable(arg: 1, scope: !53, type: !25)
|
||||
// CHECK:STDOUT: !56 = !DILocation(line: 17, column: 1, scope: !53)
|
||||
// CHECK:STDOUT: !57 = distinct !DISubprogram(name: "F__carbon_thunk", linkageName: "_CF__carbon_thunk.Base.Main", scope: null, file: !6, line: 19, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !58)
|
||||
// CHECK:STDOUT: !58 = !{!59}
|
||||
// CHECK:STDOUT: !59 = !DILocalVariable(arg: 1, scope: !57, type: !25)
|
||||
// CHECK:STDOUT: !60 = !DILocation(line: 19, column: 3, scope: !57)
|
||||
|
||||
@@ -61,6 +61,7 @@ CARBON_SEM_IR_INST_KIND(CppTemplateNameType)
|
||||
CARBON_SEM_IR_INST_KIND(CustomLayoutType)
|
||||
CARBON_SEM_IR_INST_KIND(CustomWitness)
|
||||
CARBON_SEM_IR_INST_KIND(Deref)
|
||||
CARBON_SEM_IR_INST_KIND(EnclosingClassAccess)
|
||||
CARBON_SEM_IR_INST_KIND(ErrorInst)
|
||||
CARBON_SEM_IR_INST_KIND(ExportDecl)
|
||||
CARBON_SEM_IR_INST_KIND(ExprPattern)
|
||||
|
||||
@@ -10,12 +10,20 @@
|
||||
|
||||
namespace Carbon::SemIR {
|
||||
|
||||
// Metadata tracking information about a thunk's signature, callee, and specific
|
||||
// generic parameters.
|
||||
// Metadata about a thunk.
|
||||
struct ThunkInfo {
|
||||
// The callee wrapped by the thunk.
|
||||
InstId callee_id;
|
||||
|
||||
// The signature of the thunk.
|
||||
FunctionId signature_id = FunctionId::None;
|
||||
|
||||
// If `signature_id` is generic, the specific that this thunk is for.
|
||||
SpecificId specific_id = SpecificId::None;
|
||||
|
||||
// If this is a thunk for a virtual function override, the type of the
|
||||
// `self` parameter of the override.
|
||||
TypeId override_self_type_id = TypeId::None;
|
||||
};
|
||||
|
||||
using ThunkStore = ValueStore<ThunkId, ThunkInfo, Tag<CheckIRId>>;
|
||||
|
||||
@@ -623,6 +623,20 @@ struct Deref {
|
||||
InstId pointer_id;
|
||||
};
|
||||
|
||||
// A reference to the class instance which has `element_id` at index `index`.
|
||||
struct EnclosingClassAccess {
|
||||
static constexpr auto Kind =
|
||||
// This is created from other insts, not from a node.
|
||||
InstKind::EnclosingClassAccess.Define<Parse::NodeId>(
|
||||
{.ir_name = "enclosing_class_access",
|
||||
.expr_category = ComputedExprCategory::SameAsFirstOperand,
|
||||
.constant_kind = InstConstantKind::Never});
|
||||
|
||||
TypeId type_id;
|
||||
InstId element_id;
|
||||
ElementIndex index;
|
||||
};
|
||||
|
||||
// Used when a semantic error has been detected, and a SemIR InstId is still
|
||||
// required. For example, when there is a type checking issue, this will be used
|
||||
// in the type_id. It's typically used as a cue that semantic checking doesn't
|
||||
|
||||
Reference in New Issue
Block a user