mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 15:10:12 +01:00
Export Carbon classes as base / final / abstract. (#7191)
* For Carbon `base class C`, export as a regular C++ class. * For Carbon `class C`, export with the C++ `final` keyword attribute. * For Carbon `abstract C`, mark the destructor as pure virtual in cases where no member function is abstract, or emit an error if the destructor is not virtual. To support the final point, mark the destructor of an exported class as virtual if it overrides a virtual destructor from the base class. In passing, fix a crash exporting fields if the class has an invalid base type.
This commit is contained in:
@@ -11,10 +11,14 @@
|
||||
#include "toolchain/check/cpp/location.h"
|
||||
#include "toolchain/check/cpp/type_mapping.h"
|
||||
#include "toolchain/check/function.h"
|
||||
#include "toolchain/check/import_ref.h"
|
||||
#include "toolchain/check/pattern.h"
|
||||
#include "toolchain/check/thunk.h"
|
||||
#include "toolchain/check/type.h"
|
||||
#include "toolchain/sem_ir/generic.h"
|
||||
#include "toolchain/sem_ir/mangler.h"
|
||||
#include "toolchain/sem_ir/typed_insts.h"
|
||||
#include "toolchain/sem_ir/vtable.h"
|
||||
|
||||
namespace Carbon::Check {
|
||||
|
||||
@@ -183,6 +187,9 @@ static auto GetStructTypeFields(Context& context,
|
||||
|
||||
auto object_repr_type_id =
|
||||
class_info.GetObjectRepr(context.sem_ir(), SemIR::SpecificId::None);
|
||||
if (object_repr_type_id == SemIR::ErrorInst::TypeId) {
|
||||
return {};
|
||||
}
|
||||
auto struct_type =
|
||||
context.types().GetAs<SemIR::StructType>(object_repr_type_id);
|
||||
return context.struct_type_fields().Get(struct_type.fields_id);
|
||||
@@ -771,12 +778,45 @@ auto ExportFunctionToCpp(Context& context, SemIR::LocId loc_id,
|
||||
carbon_function_decl);
|
||||
}
|
||||
|
||||
// Returns whether the given class has any abstract methods.
|
||||
static auto HasAnyAbstractMethods(Context& context,
|
||||
const SemIR::Class& class_info,
|
||||
SemIR::SpecificId class_specific_id) -> bool {
|
||||
if (class_info.vtable_decl_id == SemIR::InstId::None) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LoadImportRef(context, class_info.vtable_decl_id);
|
||||
auto vtable_decl_const_id = GetConstantValueInSpecific(
|
||||
context.sem_ir(), class_specific_id, class_info.vtable_decl_id);
|
||||
if (vtable_decl_const_id == SemIR::ErrorInst::ConstantId) {
|
||||
return false;
|
||||
}
|
||||
auto vtable_id = context.constant_values()
|
||||
.GetInstAs<SemIR::VtableDecl>(vtable_decl_const_id)
|
||||
.vtable_id;
|
||||
const auto& vtable = context.vtables().Get(vtable_id);
|
||||
for (auto virtual_fn_id :
|
||||
context.inst_blocks().Get(vtable.virtual_functions_id)) {
|
||||
auto virtual_fn = DecomposeVirtualFunction(context.sem_ir(), virtual_fn_id,
|
||||
class_specific_id);
|
||||
if (context.functions().Get(virtual_fn.function_id).virtual_modifier ==
|
||||
SemIR::Function::VirtualModifier::Abstract) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ExportDestructorToCpp(Context& context, const SemIR::Class& class_info,
|
||||
clang::CXXRecordDecl* record_decl)
|
||||
-> clang::CXXDestructorDecl* {
|
||||
SemIR::LocId loc_id(class_info.first_decl_id());
|
||||
auto clang_loc = record_decl->getLocation();
|
||||
|
||||
// TODO: Add support for exporting specific classes.
|
||||
const auto specific_id = SemIR::SpecificId::None;
|
||||
|
||||
// Create C++ destructor decl.
|
||||
auto class_type = context.ast_context().getCanonicalTagType(record_decl);
|
||||
auto name =
|
||||
@@ -784,7 +824,8 @@ auto ExportDestructorToCpp(Context& context, const SemIR::Class& class_info,
|
||||
clang::DeclarationNameInfo name_info(name, clang_loc);
|
||||
clang::QualType type = context.ast_context().getFunctionType(
|
||||
context.ast_context().VoidTy, llvm::ArrayRef<clang::QualType>(),
|
||||
clang::FunctionProtoType::ExtProtoInfo());
|
||||
clang::FunctionProtoType::ExtProtoInfo().withExceptionSpec(
|
||||
clang::EST_BasicNoexcept));
|
||||
auto* cpp_destructor_decl = clang::CXXDestructorDecl::Create(
|
||||
context.ast_context(), record_decl,
|
||||
/*StartLoc=*/clang_loc, name_info, type, /*TInfo=*/nullptr,
|
||||
@@ -792,14 +833,33 @@ auto ExportDestructorToCpp(Context& context, const SemIR::Class& class_info,
|
||||
clang::ConstexprSpecKind::Unspecified);
|
||||
cpp_destructor_decl->setAccess(clang::AS_public);
|
||||
|
||||
clang::Sema& sema = context.clang_sema();
|
||||
|
||||
// Find and register any base class virtual destructors that this destructor
|
||||
// overrides. This marks the destructor as implicitly virtual if needed.
|
||||
sema.AddOverriddenMethods(record_decl, cpp_destructor_decl);
|
||||
|
||||
// If the class is abstract and has no abstract methods, we need to mark the
|
||||
// destructor as pure virtual.
|
||||
if (class_info.inheritance_kind == SemIR::Class::InheritanceKind::Abstract &&
|
||||
!HasAnyAbstractMethods(context, class_info, specific_id)) {
|
||||
if (cpp_destructor_decl->isVirtual()) {
|
||||
cpp_destructor_decl->setIsPureVirtual(true);
|
||||
} else {
|
||||
context.TODO(class_info.definition_id,
|
||||
"exporting abstract class with no abstract methods and "
|
||||
"non-virtual destructor to C++");
|
||||
}
|
||||
}
|
||||
|
||||
// Create Carbon thunk that destroys the object, and get a C++
|
||||
// function decl for calling it.
|
||||
// TODO: Once we support exporting specific classes, export the specific
|
||||
// destructor here rather than a generic one.
|
||||
auto thunk_function_id = BuildDestroyThunk(context, loc_id, class_info);
|
||||
auto* cpp_function_decl =
|
||||
BuildCppFunctionDeclForCarbonFn(context, loc_id, thunk_function_id);
|
||||
|
||||
clang::Sema& sema = context.clang_sema();
|
||||
|
||||
// Build the destructor body.
|
||||
clang::Sema::ContextRAII context_raii(sema, cpp_destructor_decl);
|
||||
sema.ActOnStartOfFunctionDef(nullptr, cpp_destructor_decl);
|
||||
|
||||
@@ -616,6 +616,15 @@ auto CarbonExternalASTSource::CompleteType(clang::TagDecl* tag_decl) -> void {
|
||||
class_decl->startDefinition();
|
||||
CARBON_CHECK(class_decl->hasDefinition());
|
||||
|
||||
// If the Carbon class is final, mark the C++ class as also being `final`.
|
||||
// Abstract classes are handled when generating the destructor declaration.
|
||||
if (class_info.inheritance_kind == SemIR::Class::InheritanceKind::Final) {
|
||||
// TODO: Find the location of the `final` modifier and use it here.
|
||||
class_decl->addAttr(clang::FinalAttr::Create(
|
||||
context_->ast_context(),
|
||||
GetCppLocation(*context_, SemIR::LocId(class_info.definition_id))));
|
||||
}
|
||||
|
||||
// If the Carbon class has a base class that we can map into C++, add that as
|
||||
// a C++ base class.
|
||||
auto base_type_id =
|
||||
|
||||
@@ -1801,9 +1801,16 @@ static auto ImportFunction(Context& context, SemIR::LocId loc_id,
|
||||
}
|
||||
if (virtual_modifier != SemIR::Function::VirtualModifier::None) {
|
||||
// TODO: Add support for Microsoft/non-Itanium vtables.
|
||||
clang::GlobalDecl decl;
|
||||
if (auto* dtor_decl = dyn_cast<clang::CXXDestructorDecl>(method_decl)) {
|
||||
// TODO: Do we want the index of the complete or base destructor?
|
||||
decl = clang::GlobalDecl(dtor_decl, clang::Dtor_Complete);
|
||||
} else {
|
||||
decl = clang::GlobalDecl(method_decl);
|
||||
}
|
||||
virtual_index = dyn_cast<clang::ItaniumVTableContext>(
|
||||
context.ast_context().getVTableContext())
|
||||
->getMethodVTableIndex(method_decl);
|
||||
->getMethodVTableIndex(decl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+108
-3
@@ -49,8 +49,113 @@ void Qualified() {
|
||||
}
|
||||
|
||||
void MemberAccess(Carbon::A *a, Carbon::B *b) {
|
||||
// TODO: These cause a crash.
|
||||
// b->F();
|
||||
// b->G();
|
||||
b->F();
|
||||
b->G();
|
||||
}
|
||||
''';
|
||||
|
||||
// --- fail_derive_from_final.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp;
|
||||
|
||||
class Final {}
|
||||
|
||||
inline Cpp '''
|
||||
// CHECK:STDERR: fail_derive_from_final.carbon:[[@LINE+5]]:12: error: base 'Final' is marked 'final' [CppInteropParseError]
|
||||
// CHECK:STDERR: 13 | struct A : Carbon::Final {};
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR: note: 'Final' declared here [CppInteropParseNote]
|
||||
// CHECK:STDERR:
|
||||
struct A : Carbon::Final {};
|
||||
''';
|
||||
|
||||
// --- fail_abstract.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp;
|
||||
|
||||
// TODO: Add a way to give a class a virtual destructor without C++ interop.
|
||||
inline Cpp '''
|
||||
struct VirtualDestructor {
|
||||
virtual ~VirtualDestructor() {}
|
||||
};
|
||||
''';
|
||||
|
||||
// CHECK:STDERR: fail_abstract.carbon:[[@LINE+4]]:1: error: cannot access member of interface `Core.Destroy` in type `Abstract` that does not implement that interface [MissingImplInMemberAccess]
|
||||
// CHECK:STDERR: abstract class Abstract {
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
abstract class Abstract {
|
||||
extend base: Cpp.VirtualDestructor;
|
||||
}
|
||||
|
||||
inline Cpp '''
|
||||
// CHECK:STDERR: fail_abstract.carbon:[[@LINE+5]]:18: error: variable type 'Carbon::Abstract' is an abstract class [CppInteropParseError]
|
||||
// CHECK:STDERR: 26 | Carbon::Abstract x;
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR: note: unimplemented pure virtual method '~Abstract' in 'Abstract' [CppInteropParseNote]
|
||||
// CHECK:STDERR:
|
||||
Carbon::Abstract x;
|
||||
''';
|
||||
|
||||
// --- fail_todo_abstract_nonvirtual_dtor.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp;
|
||||
|
||||
// TODO: Find a way to export this to C++ as an abstract class, despite not
|
||||
// having a vptr.
|
||||
// CHECK:STDERR: fail_todo_abstract_nonvirtual_dtor.carbon:[[@LINE+8]]:1: error: semantics TODO: `exporting abstract class with no abstract methods and non-virtual destructor to C++` [SemanticsTodo]
|
||||
// CHECK:STDERR: abstract class Abstract {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_todo_abstract_nonvirtual_dtor.carbon:[[@LINE+4]]:1: error: cannot access member of interface `Core.Destroy` in type `Abstract` that does not implement that interface [MissingImplInMemberAccess]
|
||||
// CHECK:STDERR: abstract class Abstract {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
abstract class Abstract {}
|
||||
|
||||
inline Cpp '''
|
||||
class Derived : public Carbon::Abstract {};
|
||||
''';
|
||||
|
||||
// --- fail_todo_abstract_nonvirtual_dtor_but_virtual_fns.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp;
|
||||
|
||||
// TODO: We should support generating a base subobject destructor for an
|
||||
// abstract class, even though we refuse to generate a complete object
|
||||
// destructor.
|
||||
// CHECK:STDERR: fail_todo_abstract_nonvirtual_dtor_but_virtual_fns.carbon:[[@LINE+4]]:1: error: cannot access member of interface `Core.Destroy` in type `Abstract` that does not implement that interface [MissingImplInMemberAccess]
|
||||
// CHECK:STDERR: abstract class Abstract {
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
abstract class Abstract {
|
||||
abstract fn F[self: Self]();
|
||||
}
|
||||
|
||||
inline Cpp '''
|
||||
class Derived : public Carbon::Abstract {
|
||||
};
|
||||
''';
|
||||
|
||||
// --- override_virtual_dtor.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp;
|
||||
|
||||
inline Cpp '''
|
||||
struct A {
|
||||
virtual ~A() = 0;
|
||||
};
|
||||
''';
|
||||
|
||||
class B {
|
||||
extend base: Cpp.A;
|
||||
}
|
||||
|
||||
inline Cpp '''
|
||||
Carbon::B b;
|
||||
''';
|
||||
|
||||
@@ -121,3 +121,20 @@ void F() {
|
||||
a.x = 12;
|
||||
}
|
||||
''';
|
||||
|
||||
// --- fail_invalid.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
import Cpp;
|
||||
|
||||
// This should not cause a crash.
|
||||
class A {
|
||||
// CHECK:STDERR: fail_invalid.carbon:[[@LINE+4]]:16: error: name `Whoops` not found [NameNotFound]
|
||||
// CHECK:STDERR: extend base: Whoops;
|
||||
// CHECK:STDERR: ^~~~~~
|
||||
// CHECK:STDERR:
|
||||
extend base: Whoops;
|
||||
}
|
||||
|
||||
inline Cpp '''
|
||||
Carbon::A x;
|
||||
''';
|
||||
|
||||
@@ -76,8 +76,6 @@ auto DoThing() -> int {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZN6Carbon7DerivedD2Ev = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $__clang_call_terminate = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZN11FurtherBase17further_base_funcEv = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZN4Base4funcEv = comdat any
|
||||
@@ -130,33 +128,33 @@ auto DoThing() -> int {
|
||||
// CHECK:STDOUT: ret i32 %call
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: mustprogress uwtable
|
||||
// CHECK:STDOUT: define dso_local void @_Z29WorkaroundToEmitCtorAndVtablev() #0 {
|
||||
// CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define dso_local void @_Z29WorkaroundToEmitCtorAndVtablev() #1 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %d = alloca %"class.Carbon::Derived", align 8
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %d) #5
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %d) #5
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %d)
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %d) #5
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %d) #4
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %d) #4
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %d) #4
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %d) #4
|
||||
// CHECK:STDOUT: ret void
|
||||
// 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: declare void @llvm.lifetime.start.p0(ptr captures(none)) #2
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon7DerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr #2 comdat align 2 {
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon7DerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %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 !18
|
||||
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
|
||||
// CHECK:STDOUT: call void @_ZN4BaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this1) #5
|
||||
// CHECK:STDOUT: call void @_ZN4BaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this1) #4
|
||||
// CHECK:STDOUT: store ptr getelementptr inbounds inrange(-16, 16) ({ [4 x ptr] }, ptr @_ZTVN6Carbon7DerivedE, i32 0, i32 0, i32 2), ptr %this1, align 8, !tbaa !16
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon7DerivedD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %this) unnamed_addr #2 comdat align 2 {
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon7DerivedD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %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 !18
|
||||
@@ -167,7 +165,7 @@ auto DoThing() -> int {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
|
||||
// CHECK:STDOUT: declare void @llvm.lifetime.end.p0(ptr captures(none)) #1
|
||||
// CHECK:STDOUT: declare void @llvm.lifetime.end.p0(ptr captures(none)) #2
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: mustprogress uwtable
|
||||
// CHECK:STDOUT: define dso_local noundef i32 @_Z7DoThingv() #0 personality ptr @__gxx_personality_v0 {
|
||||
@@ -175,14 +173,14 @@ auto DoThing() -> int {
|
||||
// CHECK:STDOUT: %d = alloca %"class.Carbon::Derived", align 8
|
||||
// CHECK:STDOUT: %exn.slot = alloca ptr, align 8
|
||||
// CHECK:STDOUT: %ehselector.slot = alloca i32, align 4
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %d) #5
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %d) #5
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %d) #4
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %d) #4
|
||||
// CHECK:STDOUT: %call = invoke noundef i32 @_Z3UseR4Base(ptr noundef nonnull align 8 dereferenceable(12) %d)
|
||||
// CHECK:STDOUT: to label %invoke.cont unwind label %lpad
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: invoke.cont: ; preds = %entry
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %d)
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %d) #5
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %d) #4
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %d) #4
|
||||
// CHECK:STDOUT: ret i32 %call
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: lpad: ; preds = %entry
|
||||
@@ -192,26 +190,16 @@ auto DoThing() -> int {
|
||||
// CHECK:STDOUT: store ptr %1, ptr %exn.slot, align 8
|
||||
// CHECK:STDOUT: %2 = extractvalue { ptr, i32 } %0, 1
|
||||
// CHECK:STDOUT: store i32 %2, ptr %ehselector.slot, align 4
|
||||
// CHECK:STDOUT: invoke void @_ZN6Carbon7DerivedD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %d)
|
||||
// CHECK:STDOUT: to label %invoke.cont1 unwind label %terminate.lpad
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: invoke.cont1: ; preds = %lpad
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %d) #5
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %d) #4
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %d) #4
|
||||
// CHECK:STDOUT: br label %eh.resume
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: eh.resume: ; preds = %invoke.cont1
|
||||
// CHECK:STDOUT: eh.resume: ; preds = %lpad
|
||||
// CHECK:STDOUT: %exn = load ptr, ptr %exn.slot, align 8
|
||||
// CHECK:STDOUT: %sel = load i32, ptr %ehselector.slot, align 4
|
||||
// CHECK:STDOUT: %lpad.val = insertvalue { ptr, i32 } poison, ptr %exn, 0
|
||||
// CHECK:STDOUT: %lpad.val2 = insertvalue { ptr, i32 } %lpad.val, i32 %sel, 1
|
||||
// CHECK:STDOUT: resume { ptr, i32 } %lpad.val2
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: terminate.lpad: ; preds = %lpad
|
||||
// CHECK:STDOUT: %3 = landingpad { ptr, i32 }
|
||||
// CHECK:STDOUT: catch ptr null
|
||||
// CHECK:STDOUT: %4 = extractvalue { ptr, i32 } %3, 0
|
||||
// CHECK:STDOUT: call void @__clang_call_terminate(ptr %4) #7
|
||||
// CHECK:STDOUT: unreachable
|
||||
// CHECK:STDOUT: %lpad.val1 = insertvalue { ptr, i32 } %lpad.val, i32 %sel, 1
|
||||
// CHECK:STDOUT: resume { ptr, i32 } %lpad.val1
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; uselistorder directives
|
||||
// CHECK:STDOUT: uselistorder ptr %d, { 0, 2, 1, 3, 4, 5, 6 }
|
||||
@@ -219,19 +207,8 @@ auto DoThing() -> int {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: declare i32 @__gxx_personality_v0(...)
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: noinline noreturn nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr hidden void @__clang_call_terminate(ptr noundef %0) #3 comdat {
|
||||
// CHECK:STDOUT: %2 = call ptr @__cxa_begin_catch(ptr %0) #5
|
||||
// CHECK:STDOUT: call void @_ZSt9terminatev() #7
|
||||
// CHECK:STDOUT: unreachable
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: declare ptr @__cxa_begin_catch(ptr)
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: declare void @_ZSt9terminatev()
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local noundef i32 @_ZN11FurtherBase17further_base_funcEv(ptr noundef nonnull align 8 dereferenceable(8) %this) unnamed_addr #4 comdat align 2 {
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local noundef i32 @_ZN11FurtherBase17further_base_funcEv(ptr noundef nonnull align 8 dereferenceable(8) %this) unnamed_addr #1 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 !20
|
||||
@@ -240,7 +217,7 @@ auto DoThing() -> int {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local noundef i32 @_ZN4Base4funcEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr #4 comdat align 2 {
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local noundef i32 @_ZN4Base4funcEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr #1 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 !11
|
||||
@@ -249,43 +226,43 @@ auto DoThing() -> int {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define i32 @_Cother_func.Derived.Main(ptr %self) #5 !dbg !22 {
|
||||
// CHECK:STDOUT: define i32 @_Cother_func.Derived.Main(ptr %self) #4 !dbg !22 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret i32 3, !dbg !29
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
|
||||
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.Derived.Main"(ptr %self) #6 !dbg !30 {
|
||||
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.Derived.Main"(ptr %self) #5 !dbg !30 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @"_COp.12e0d0434542305a:core.Destroy.Core"(ptr %self), !dbg !35
|
||||
// CHECK:STDOUT: ret void, !dbg !35
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.bfe31446004e2b71:core.Destroy.Core"(ptr %self) #5 !dbg !36 {
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.bfe31446004e2b71:core.Destroy.Core"(ptr %self) #4 !dbg !36 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !39
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.12e0d0434542305a:core.Destroy.Core"(ptr %self) #5 !dbg !40 {
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.12e0d0434542305a:core.Destroy.Core"(ptr %self) #4 !dbg !40 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !43
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN4BaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr #2 comdat align 2 {
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN4BaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %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 !11
|
||||
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
|
||||
// CHECK:STDOUT: call void @_ZN11FurtherBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %this1) #5
|
||||
// CHECK:STDOUT: call void @_ZN11FurtherBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %this1) #4
|
||||
// CHECK:STDOUT: store ptr getelementptr inbounds inrange(-16, 16) ({ [4 x ptr] }, ptr @_ZTV4Base, i32 0, i32 0, i32 2), ptr %this1, align 8, !tbaa !16
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN11FurtherBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %this) unnamed_addr #2 comdat align 2 {
|
||||
// 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 !20
|
||||
@@ -302,13 +279,11 @@ auto DoThing() -> int {
|
||||
// CHECK:STDOUT: uselistorder ptr @_ZN4Base4funcEv, { 2, 1, 0 }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: attributes #0 = { mustprogress 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 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||
// CHECK:STDOUT: attributes #2 = { inlinehint 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" }
|
||||
// CHECK:STDOUT: attributes #3 = { noinline noreturn nounwind uwtable "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 #4 = { 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" }
|
||||
// CHECK:STDOUT: attributes #5 = { nounwind }
|
||||
// CHECK:STDOUT: attributes #6 = { alwaysinline nounwind }
|
||||
// CHECK:STDOUT: attributes #7 = { noreturn nounwind }
|
||||
// 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" }
|
||||
// CHECK:STDOUT: attributes #2 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||
// CHECK:STDOUT: attributes #3 = { inlinehint 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" }
|
||||
// CHECK:STDOUT: attributes #4 = { nounwind }
|
||||
// CHECK:STDOUT: attributes #5 = { alwaysinline nounwind }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4}
|
||||
// CHECK:STDOUT: !llvm.dbg.cu = !{!5}
|
||||
|
||||
@@ -0,0 +1,338 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/int.carbon
|
||||
// EXTRA-ARGS: --clang-arg=-fno-exceptions
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/interop/cpp/class/virtual_fn.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/interop/cpp/class/virtual_fn.carbon
|
||||
|
||||
// --- override_virtual_dtor.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp;
|
||||
|
||||
inline Cpp '''
|
||||
struct A {
|
||||
virtual ~A() = 0;
|
||||
};
|
||||
''';
|
||||
|
||||
class Final {
|
||||
extend base: Cpp.A;
|
||||
}
|
||||
|
||||
base class Base {
|
||||
extend base: Cpp.A;
|
||||
}
|
||||
|
||||
inline Cpp '''
|
||||
void delete_new_Final() {
|
||||
// vtable should refer to Carbon::Final's dtor.
|
||||
auto* p = new Carbon::Final;
|
||||
// Perform a devirtualized call to Final destructor.
|
||||
delete p;
|
||||
}
|
||||
|
||||
void delete_new_Base() {
|
||||
// vtable should refer to Carbon::Base's dtor.
|
||||
auto* p = new Carbon::Base;
|
||||
// Perform a virtual call to destructor.
|
||||
delete p;
|
||||
}
|
||||
''';
|
||||
|
||||
// CHECK:STDOUT: ; ModuleID = 'override_virtual_dtor.carbon'
|
||||
// CHECK:STDOUT: source_filename = "override_virtual_dtor.carbon"
|
||||
// CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
|
||||
// CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu"
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZN6Carbon5FinalC2Ev = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZN6Carbon5FinalD2Ev = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZN6Carbon4BaseC2Ev = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZN1AC2Ev = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZN6Carbon5FinalD0Ev = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZN6Carbon4BaseD2Ev = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZN6Carbon4BaseD0Ev = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZTVN6Carbon5FinalE = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZTIN6Carbon5FinalE = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZTSN6Carbon5FinalE = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZTI1A = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZTS1A = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZTV1A = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZTVN6Carbon4BaseE = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZTIN6Carbon4BaseE = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZTSN6Carbon4BaseE = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: @"_CFinal.Main.$vtable" = unnamed_addr constant [0 x i32] zeroinitializer
|
||||
// CHECK:STDOUT: @"_CBase.Main.$vtable" = unnamed_addr constant [0 x i32] zeroinitializer
|
||||
// CHECK:STDOUT: @_ZTVN6Carbon5FinalE = linkonce_odr dso_local unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTIN6Carbon5FinalE, ptr @_ZN6Carbon5FinalD2Ev, ptr @_ZN6Carbon5FinalD0Ev] }, comdat, align 8
|
||||
// CHECK:STDOUT: @_ZTIN6Carbon5FinalE = linkonce_odr dso_local constant { ptr, ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2), ptr @_ZTSN6Carbon5FinalE, ptr @_ZTI1A }, comdat, align 8
|
||||
// CHECK:STDOUT: @_ZTVN10__cxxabiv120__si_class_type_infoE = external global [0 x ptr]
|
||||
// CHECK:STDOUT: @_ZTSN6Carbon5FinalE = linkonce_odr dso_local constant [16 x i8] c"N6Carbon5FinalE\00", comdat, align 1
|
||||
// CHECK:STDOUT: @_ZTI1A = linkonce_odr dso_local constant { ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), ptr @_ZTS1A }, comdat, align 8
|
||||
// CHECK:STDOUT: @_ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr]
|
||||
// CHECK:STDOUT: @_ZTS1A = linkonce_odr dso_local constant [3 x i8] c"1A\00", comdat, align 1
|
||||
// CHECK:STDOUT: @_ZTV1A = linkonce_odr dso_local unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTI1A, ptr @__cxa_pure_virtual, ptr @__cxa_pure_virtual] }, comdat, align 8
|
||||
// CHECK:STDOUT: @_ZTVN6Carbon4BaseE = linkonce_odr dso_local unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTIN6Carbon4BaseE, ptr @_ZN6Carbon4BaseD2Ev, ptr @_ZN6Carbon4BaseD0Ev] }, comdat, align 8
|
||||
// CHECK:STDOUT: @_ZTIN6Carbon4BaseE = linkonce_odr dso_local constant { ptr, ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2), ptr @_ZTSN6Carbon4BaseE, ptr @_ZTI1A }, comdat, align 8
|
||||
// CHECK:STDOUT: @_ZTSN6Carbon4BaseE = linkonce_odr dso_local constant [15 x i8] c"N6Carbon4BaseE\00", comdat, align 1
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define dso_local void @_Z16delete_new_Finalv() #0 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %p = alloca ptr, align 8
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %p) #7
|
||||
// CHECK:STDOUT: %call = call noalias noundef nonnull ptr @_Znwm(i64 noundef 8) #8
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon5FinalC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %call) #7
|
||||
// CHECK:STDOUT: store ptr %call, ptr %p, align 8, !tbaa !11
|
||||
// CHECK:STDOUT: %0 = load ptr, ptr %p, align 8, !tbaa !11
|
||||
// CHECK:STDOUT: %isnull = icmp eq ptr %0, null
|
||||
// CHECK:STDOUT: br i1 %isnull, label %delete.end, label %delete.notnull
|
||||
// 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) #7
|
||||
// CHECK:STDOUT: call void @_ZdlPvm(ptr noundef %0, i64 noundef 8) #9
|
||||
// CHECK:STDOUT: br label %delete.end
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: delete.end: ; preds = %delete.notnull, %entry
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %p) #7
|
||||
// CHECK:STDOUT: ret void
|
||||
// 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:
|
||||
// CHECK:STDOUT: ; Function Attrs: nobuiltin allocsize(0)
|
||||
// CHECK:STDOUT: declare noundef nonnull ptr @_Znwm(i64 noundef) #2
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon5FinalC2Ev(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 !11
|
||||
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
|
||||
// CHECK:STDOUT: call void @_ZN1AC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %this1) #7
|
||||
// CHECK:STDOUT: store ptr getelementptr inbounds inrange(-16, 16) ({ [4 x ptr] }, ptr @_ZTVN6Carbon5FinalE, i32 0, i32 0, i32 2), ptr %this1, align 8, !tbaa !14
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon5FinalD2Ev(ptr noundef nonnull align 8 dead_on_return(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 !11
|
||||
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
|
||||
// CHECK:STDOUT: call void @"_C__destroy_thunk:thunk.Final.Main"(ptr noundef nonnull align 8 dereferenceable(8) %this1)
|
||||
// CHECK:STDOUT: call void @_ZN1AD2Ev(ptr noundef nonnull align 8 dead_on_return(8) dereferenceable(8) %this1) #7
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nobuiltin nounwind
|
||||
// CHECK:STDOUT: declare void @_ZdlPvm(ptr noundef, i64 noundef) #4
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
|
||||
// CHECK:STDOUT: declare void @llvm.lifetime.end.p0(ptr captures(none)) #1
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define dso_local void @_Z15delete_new_Basev() #0 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %p = alloca ptr, align 8
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %p) #7
|
||||
// CHECK:STDOUT: %call = call noalias noundef nonnull ptr @_Znwm(i64 noundef 8) #8
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon4BaseC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %call) #7
|
||||
// CHECK:STDOUT: store ptr %call, ptr %p, align 8, !tbaa !16
|
||||
// CHECK:STDOUT: %0 = load ptr, ptr %p, align 8, !tbaa !16
|
||||
// CHECK:STDOUT: %isnull = icmp eq ptr %0, null
|
||||
// CHECK:STDOUT: br i1 %isnull, label %delete.end, label %delete.notnull
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: delete.notnull: ; preds = %entry
|
||||
// CHECK:STDOUT: %vtable = load ptr, ptr %0, align 8, !tbaa !14
|
||||
// CHECK:STDOUT: %vfn = getelementptr inbounds ptr, ptr %vtable, i64 1
|
||||
// CHECK:STDOUT: %1 = load ptr, ptr %vfn, align 8
|
||||
// CHECK:STDOUT: call void %1(ptr noundef nonnull align 8 dead_on_return(8) dereferenceable(8) %0) #7
|
||||
// CHECK:STDOUT: br label %delete.end
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: delete.end: ; preds = %delete.notnull, %entry
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %p) #7
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon4BaseC2Ev(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 !16
|
||||
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
|
||||
// CHECK:STDOUT: call void @_ZN1AC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %this1) #7
|
||||
// CHECK:STDOUT: store ptr getelementptr inbounds inrange(-16, 16) ({ [4 x ptr] }, ptr @_ZTVN6Carbon4BaseE, i32 0, i32 0, i32 2), ptr %this1, align 8, !tbaa !14
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
|
||||
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.Final.Main"(ptr %self) #5 !dbg !18 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @"_COp.4472d163614a5082:core.Destroy.Core"(ptr %self), !dbg !24
|
||||
// CHECK:STDOUT: ret void, !dbg !24
|
||||
// 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 #6
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.446491dd079aaad2:core.Destroy.Core"(ptr %self) #7 !dbg !25 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !28
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.4472d163614a5082:core.Destroy.Core"(ptr %self) #7 !dbg !29 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !32
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
|
||||
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.Base.Main"(ptr %self) #5 !dbg !33 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @"_COp.96a711151205ee34: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.96a711151205ee34:core.Destroy.Core"(ptr %self) #7 !dbg !37 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !40
|
||||
// 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 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %this.addr = alloca ptr, align 8
|
||||
// CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !41
|
||||
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
|
||||
// CHECK:STDOUT: store ptr getelementptr inbounds inrange(-16, 16) ({ [4 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 2), ptr %this1, align 8, !tbaa !14
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon5FinalD0Ev(ptr noundef nonnull align 8 dead_on_return(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 !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) #7
|
||||
// CHECK:STDOUT: call void @_ZdlPvm(ptr noundef %this1, i64 noundef 8) #9
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: declare void @__cxa_pure_virtual() unnamed_addr
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: declare void @_ZN1AD2Ev(ptr noundef nonnull align 8 dead_on_return(8) dereferenceable(8)) unnamed_addr #6
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon4BaseD2Ev(ptr noundef nonnull align 8 dead_on_return(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 !16
|
||||
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
|
||||
// CHECK:STDOUT: store ptr getelementptr inbounds inrange(-16, 16) ({ [4 x ptr] }, ptr @_ZTVN6Carbon4BaseE, i32 0, i32 0, i32 2), ptr %this1, align 8, !tbaa !14
|
||||
// CHECK:STDOUT: call void @"_C__destroy_thunk:thunk.Base.Main"(ptr noundef nonnull align 8 dereferenceable(8) %this1)
|
||||
// CHECK:STDOUT: call void @_ZN1AD2Ev(ptr noundef nonnull align 8 dead_on_return(8) dereferenceable(8) %this1) #7
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon4BaseD0Ev(ptr noundef nonnull align 8 dead_on_return(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 !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) #7
|
||||
// CHECK:STDOUT: call void @_ZdlPvm(ptr noundef %this1, i64 noundef 8) #9
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; uselistorder directives
|
||||
// CHECK:STDOUT: uselistorder ptr @_ZN6Carbon5FinalD2Ev, { 2, 1, 0 }
|
||||
// CHECK:STDOUT: uselistorder ptr @_ZN1AC2Ev, { 1, 0 }
|
||||
// CHECK:STDOUT: uselistorder ptr @__cxa_pure_virtual, { 1, 0 }
|
||||
// CHECK:STDOUT: uselistorder ptr @_ZN6Carbon4BaseD2Ev, { 1, 0 }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: attributes #0 = { 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" }
|
||||
// CHECK:STDOUT: attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||
// CHECK:STDOUT: attributes #2 = { nobuiltin allocsize(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 #3 = { inlinehint 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" }
|
||||
// CHECK:STDOUT: attributes #4 = { nobuiltin 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 #5 = { alwaysinline nounwind }
|
||||
// CHECK:STDOUT: attributes #6 = { 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 #7 = { nounwind }
|
||||
// CHECK:STDOUT: attributes #8 = { builtin allocsize(0) }
|
||||
// CHECK:STDOUT: attributes #9 = { builtin nounwind }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4}
|
||||
// CHECK:STDOUT: !llvm.dbg.cu = !{!5}
|
||||
// CHECK:STDOUT: !llvm.errno.tbaa = !{!7}
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5}
|
||||
// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
// CHECK:STDOUT: !2 = !{i32 8, !"PIC Level", i32 2}
|
||||
// CHECK:STDOUT: !3 = !{i32 7, !"PIE Level", i32 2}
|
||||
// CHECK:STDOUT: !4 = !{i32 7, !"uwtable", i32 2}
|
||||
// CHECK:STDOUT: !5 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !6, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
|
||||
// CHECK:STDOUT: !6 = !DIFile(filename: "override_virtual_dtor.carbon", directory: "")
|
||||
// CHECK:STDOUT: !7 = !{!8, !8, i64 0}
|
||||
// CHECK:STDOUT: !8 = !{!"int", !9, i64 0}
|
||||
// CHECK:STDOUT: !9 = !{!"omnipotent char", !10, i64 0}
|
||||
// CHECK:STDOUT: !10 = !{!"Simple C++ TBAA"}
|
||||
// CHECK:STDOUT: !11 = !{!12, !12, i64 0}
|
||||
// CHECK:STDOUT: !12 = !{!"p1 _ZTSN6Carbon5FinalE", !13, i64 0}
|
||||
// CHECK:STDOUT: !13 = !{!"any pointer", !9, i64 0}
|
||||
// CHECK:STDOUT: !14 = !{!15, !15, i64 0}
|
||||
// CHECK:STDOUT: !15 = !{!"vtable pointer", !10, i64 0}
|
||||
// CHECK:STDOUT: !16 = !{!17, !17, i64 0}
|
||||
// CHECK:STDOUT: !17 = !{!"p1 _ZTSN6Carbon4BaseE", !13, i64 0}
|
||||
// CHECK:STDOUT: !18 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.Final.Main", scope: null, file: !6, line: 11, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !22)
|
||||
// CHECK:STDOUT: !19 = !DISubroutineType(types: !20)
|
||||
// CHECK:STDOUT: !20 = !{null, !21}
|
||||
// CHECK:STDOUT: !21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
|
||||
// CHECK:STDOUT: !22 = !{!23}
|
||||
// CHECK:STDOUT: !23 = !DILocalVariable(arg: 1, scope: !18, type: !21)
|
||||
// CHECK:STDOUT: !24 = !DILocation(line: 11, column: 1, scope: !18)
|
||||
// CHECK:STDOUT: !25 = distinct !DISubprogram(name: "Op", linkageName: "_COp.446491dd079aaad2:core.Destroy.Core", scope: null, file: !6, line: 11, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !26)
|
||||
// CHECK:STDOUT: !26 = !{!27}
|
||||
// CHECK:STDOUT: !27 = !DILocalVariable(arg: 1, scope: !25, type: !21)
|
||||
// CHECK:STDOUT: !28 = !DILocation(line: 11, column: 1, scope: !25)
|
||||
// CHECK:STDOUT: !29 = distinct !DISubprogram(name: "Op", linkageName: "_COp.4472d163614a5082:core.Destroy.Core", scope: null, file: !6, line: 11, 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: 11, column: 1, scope: !29)
|
||||
// CHECK:STDOUT: !33 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.Base.Main", scope: null, file: !6, line: 15, 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: 15, column: 1, scope: !33)
|
||||
// CHECK:STDOUT: !37 = distinct !DISubprogram(name: "Op", linkageName: "_COp.96a711151205ee34:core.Destroy.Core", scope: null, file: !6, line: 15, 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: 15, column: 1, scope: !37)
|
||||
// CHECK:STDOUT: !41 = !{!42, !42, i64 0}
|
||||
// CHECK:STDOUT: !42 = !{!"p1 _ZTS1A", !13, i64 0}
|
||||
@@ -169,7 +169,7 @@ fn G() {
|
||||
// CHECK:STDOUT: %a = alloca %"class.Carbon::A", align 8
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %a) #5
|
||||
// CHECK:STDOUT: call void @_ZN6CarbonL5CallAEPNS_1AE(ptr noundef %a)
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %a)
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %a) #5
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %a) #5
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
@@ -205,7 +205,7 @@ fn G() {
|
||||
// CHECK:STDOUT: %b = alloca %"class.Carbon::B", align 8
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %b) #5
|
||||
// CHECK:STDOUT: call void @_ZN6CarbonL5CallBEPNS_1BE(ptr noundef %b)
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1BD2Ev(ptr noundef nonnull align 8 dead_on_return(16) dereferenceable(16) %b)
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1BD2Ev(ptr noundef nonnull align 8 dead_on_return(16) dereferenceable(16) %b) #5
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %b) #5
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
@@ -227,7 +227,7 @@ fn G() {
|
||||
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
|
||||
// CHECK:STDOUT: call void @"_C__destroy_thunk:thunk.B.Main"(ptr noundef nonnull align 8 dereferenceable(16) %this1)
|
||||
// CHECK:STDOUT: %a = getelementptr inbounds nuw %"class.Carbon::B", ptr %this1, i32 0, i32 0
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %a)
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %a) #5
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
@@ -238,7 +238,7 @@ fn G() {
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %c) #5
|
||||
// CHECK:STDOUT: call void @_ZN6CarbonL5CallCEPNS_1CE(ptr noundef %c)
|
||||
// CHECK:STDOUT: call void @_ZN6CarbonL5CallAEPNS_1AE(ptr noundef %c)
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1CD2Ev(ptr noundef nonnull align 8 dead_on_return(16) dereferenceable(16) %c)
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1CD2Ev(ptr noundef nonnull align 8 dead_on_return(16) dereferenceable(16) %c) #5
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %c) #5
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
@@ -259,7 +259,7 @@ fn G() {
|
||||
// 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 @"_C__destroy_thunk:thunk.C.Main"(ptr noundef nonnull align 8 dereferenceable(16) %this1)
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %this1)
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %this1) #5
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
|
||||
+12
-12
@@ -77,8 +77,8 @@ fn CallCallF() { Cpp.CallF(); }
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %ref.tmp = alloca %"class.Carbon::A", align 1
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %ref.tmp) #4
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1A1FEv(ptr noundef nonnull align 1 dereferenceable(1) %ref.tmp)
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 dereferenceable(1) %ref.tmp)
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1A1FEv(ptr noundef nonnull align 1 %ref.tmp)
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 %ref.tmp) #4
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %ref.tmp) #4
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
@@ -87,22 +87,22 @@ fn CallCallF() { Cpp.CallF(); }
|
||||
// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #1
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define internal void @_ZN6Carbon1A1FEv(ptr noundef nonnull align 1 dereferenceable(1) %this) #2 align 2 {
|
||||
// CHECK:STDOUT: define internal void @_ZN6Carbon1A1FEv(ptr noundef nonnull align 1 %this) #2 align 2 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %this.addr = alloca ptr, align 8
|
||||
// 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 @_CF__carbon_thunk.A.Main(ptr noundef nonnull align 1 dereferenceable(1) %this1)
|
||||
// CHECK:STDOUT: call void @_CF__carbon_thunk.A.Main(ptr noundef nonnull align 1 %this1)
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 dereferenceable(1) %this) unnamed_addr #3 comdat align 2 {
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 %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 !11
|
||||
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
|
||||
// CHECK:STDOUT: call void @"_C__destroy_thunk:thunk.A.Main"(ptr noundef nonnull align 1 dereferenceable(1) %this1)
|
||||
// CHECK:STDOUT: call void @"_C__destroy_thunk:thunk.A.Main"(ptr noundef nonnull align 1 %this1)
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
@@ -193,8 +193,8 @@ fn CallCallF() { Cpp.CallF(); }
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %ref.tmp = alloca %"class.Carbon::A", align 1
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %ref.tmp) #4
|
||||
// CHECK:STDOUT: %call = call noundef i32 @_ZN6Carbon1A1FEi(ptr noundef nonnull align 1 dereferenceable(1) %ref.tmp, i32 noundef 123)
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 dereferenceable(1) %ref.tmp)
|
||||
// CHECK:STDOUT: %call = call noundef i32 @_ZN6Carbon1A1FEi(ptr noundef nonnull align 1 %ref.tmp, i32 noundef 123)
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 %ref.tmp) #4
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %ref.tmp) #4
|
||||
// CHECK:STDOUT: ret i32 %call
|
||||
// CHECK:STDOUT: }
|
||||
@@ -203,7 +203,7 @@ fn CallCallF() { Cpp.CallF(); }
|
||||
// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #1
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define internal noundef i32 @_ZN6Carbon1A1FEi(ptr noundef nonnull align 1 dereferenceable(1) %this, i32 noundef %0) #2 align 2 {
|
||||
// CHECK:STDOUT: define internal noundef i32 @_ZN6Carbon1A1FEi(ptr noundef nonnull align 1 %this, i32 noundef %0) #2 align 2 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %retval = alloca i32, align 4
|
||||
// CHECK:STDOUT: %this.addr = alloca ptr, align 8
|
||||
@@ -211,18 +211,18 @@ fn CallCallF() { Cpp.CallF(); }
|
||||
// CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !11
|
||||
// CHECK:STDOUT: store i32 %0, ptr %.addr, align 4, !tbaa !7
|
||||
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
|
||||
// CHECK:STDOUT: call void @_CF__carbon_thunk.A.Main(ptr noundef nonnull align 1 dereferenceable(1) %this1, ptr noundef nonnull align 4 dereferenceable(4) %.addr, ptr noundef nonnull align 4 dereferenceable(4) %retval)
|
||||
// CHECK:STDOUT: call void @_CF__carbon_thunk.A.Main(ptr noundef nonnull align 1 %this1, ptr noundef nonnull align 4 dereferenceable(4) %.addr, ptr noundef nonnull align 4 dereferenceable(4) %retval)
|
||||
// CHECK:STDOUT: %1 = load i32, ptr %retval, align 4
|
||||
// CHECK:STDOUT: ret i32 %1
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 dereferenceable(1) %this) unnamed_addr #3 comdat align 2 {
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 %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 !11
|
||||
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
|
||||
// CHECK:STDOUT: call void @"_C__destroy_thunk:thunk.A.Main"(ptr noundef nonnull align 1 dereferenceable(1) %this1)
|
||||
// CHECK:STDOUT: call void @"_C__destroy_thunk:thunk.A.Main"(ptr noundef nonnull align 1 %this1)
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
|
||||
Reference in New Issue
Block a user