Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -514,8 +514,8 @@ /// correct type, and the caller will bitcast the function to the correct /// prototype. const CGFunctionInfo & -CodeGenTypes::arrangeMSMemberPointerThunk(const CXXMethodDecl *MD) { - assert(MD->isVirtual() && "only virtual memptrs have thunks"); +CodeGenTypes::arrangeUnprototypedMustTailThunk(const CXXMethodDecl *MD) { + assert(MD->isVirtual() && "only methods have thunks"); CanQual FTP = GetFormalType(MD); CanQualType ArgTys[] = { GetThisType(Context, MD->getParent()) }; return arrangeLLVMFunctionInfo(Context.VoidTy, /*instanceMethod=*/false, Index: clang/lib/CodeGen/CGVTables.h =================================================================== --- clang/lib/CodeGen/CGVTables.h +++ clang/lib/CodeGen/CGVTables.h @@ -57,12 +57,10 @@ /// Cache for the deleted virtual member call function. llvm::Constant *DeletedVirtualFn = nullptr; - /// emitThunk - Emit a single thunk. - void emitThunk(GlobalDecl GD, const ThunkInfo &Thunk, bool ForVTable); - - /// maybeEmitThunkForVTable - Emit the given thunk for the vtable if needed by - /// the ABI. - void maybeEmitThunkForVTable(GlobalDecl GD, const ThunkInfo &Thunk); + /// Get the address of a thunk and emit it if necessary. + llvm::Constant *maybeEmitThunk(GlobalDecl GD, + const ThunkInfo &ThunkAdjustments, + bool ForVTable); void addVTableComponent(ConstantArrayBuilder &builder, const VTableLayout &layout, unsigned idx, Index: clang/lib/CodeGen/CGVTables.cpp =================================================================== --- clang/lib/CodeGen/CGVTables.cpp +++ clang/lib/CodeGen/CGVTables.cpp @@ -31,21 +31,9 @@ CodeGenVTables::CodeGenVTables(CodeGenModule &CGM) : CGM(CGM), VTContext(CGM.getContext().getVTableContext()) {} -llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, - const ThunkInfo &Thunk) { - const CXXMethodDecl *MD = cast(GD.getDecl()); - - // Compute the mangled name. - SmallString<256> Name; - llvm::raw_svector_ostream Out(Name); - if (const CXXDestructorDecl* DD = dyn_cast(MD)) - getCXXABI().getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), - Thunk.This, Out); - else - getCXXABI().getMangleContext().mangleThunk(MD, Thunk, Out); - - llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(GD); - return GetOrCreateLLVMFunction(Name, Ty, GD, /*ForVTable=*/true, +llvm::Constant *CodeGenModule::GetAddrOfThunk(StringRef Name, llvm::Type *FnTy, + GlobalDecl GD) { + return GetOrCreateLLVMFunction(Name, FnTy, GD, /*ForVTable=*/true, /*DontDefer=*/true, /*IsThunk=*/true); } @@ -235,7 +223,8 @@ } void CodeGenFunction::StartThunk(llvm::Function *Fn, GlobalDecl GD, - const CGFunctionInfo &FnInfo) { + const CGFunctionInfo &FnInfo, + bool IsUnprototyped) { assert(!CurGD.getDecl() && "CurGD was already set!"); CurGD = GD; CurFuncIsThunk = true; @@ -254,11 +243,14 @@ // Create the implicit 'this' parameter declaration. CGM.getCXXABI().buildThisParam(*this, FunctionArgs); - // Add the rest of the parameters. - FunctionArgs.append(MD->param_begin(), MD->param_end()); + // Add the rest of the parameters, if we have a prototype to work with. + if (!IsUnprototyped) { + FunctionArgs.append(MD->param_begin(), MD->param_end()); - if (isa(MD)) - CGM.getCXXABI().addImplicitStructorParams(*this, ResultType, FunctionArgs); + if (isa(MD)) + CGM.getCXXABI().addImplicitStructorParams(*this, ResultType, + FunctionArgs); + } // Start defining the function. auto NL = ApplyDebugLocation::CreateEmpty(*this); @@ -284,7 +276,8 @@ } void CodeGenFunction::EmitCallAndReturnForThunk(llvm::Constant *CalleePtr, - const ThunkInfo *Thunk) { + const ThunkInfo *Thunk, + bool IsUnprototyped) { assert(isa(CurGD.getDecl()) && "Please use a new CGF for this thunk"); const CXXMethodDecl *MD = cast(CurGD.getDecl()); @@ -295,13 +288,17 @@ *this, LoadCXXThisAddress(), Thunk->This) : LoadCXXThis(); - if (CurFnInfo->usesInAlloca()) { + if (CurFnInfo->usesInAlloca() || IsUnprototyped) { // We don't handle return adjusting thunks, because they require us to call // the copy constructor. For now, fall through and pretend the return // adjustment was empty so we don't crash. if (Thunk && !Thunk->Return.isEmpty()) { - CGM.ErrorUnsupported( - MD, "non-trivial argument copy for return-adjusting thunk"); + if (IsUnprototyped) + CGM.ErrorUnsupported( + MD, "return-adjusting thunk with incomplete parameter type"); + else + CGM.ErrorUnsupported( + MD, "non-trivial argument copy for return-adjusting thunk"); } EmitMustTailThunk(MD, AdjustedThisPtr, CalleePtr); return; @@ -428,55 +425,98 @@ } void CodeGenFunction::generateThunk(llvm::Function *Fn, - const CGFunctionInfo &FnInfo, - GlobalDecl GD, const ThunkInfo &Thunk) { - StartThunk(Fn, GD, FnInfo); + const CGFunctionInfo &FnInfo, GlobalDecl GD, + const ThunkInfo &Thunk, + bool IsUnprototyped) { + StartThunk(Fn, GD, FnInfo, IsUnprototyped); // Create a scope with an artificial location for the body of this function. auto AL = ApplyDebugLocation::CreateArtificial(*this); - // Get our callee. - llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().arrangeGlobalDeclaration(GD)); + // Get our callee. Use a placeholder type if this method is unprototyped so + // that CodeGenModule doesn't try to set attributes. + llvm::Type *Ty; + if (IsUnprototyped) + Ty = llvm::StructType::get(getLLVMContext()); + else + Ty = CGM.getTypes().GetFunctionType(FnInfo); + llvm::Constant *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true); + // Fix up the function type for an unprototyped musttail call. + if (IsUnprototyped) + Callee = llvm::ConstantExpr::getBitCast(Callee, Fn->getType()); + // Make the call and return the result. - EmitCallAndReturnForThunk(Callee, &Thunk); + EmitCallAndReturnForThunk(Callee, &Thunk, IsUnprototyped); } -void CodeGenVTables::emitThunk(GlobalDecl GD, const ThunkInfo &Thunk, - bool ForVTable) { - const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeGlobalDeclaration(GD); +static bool shouldEmitVTableThunk(CodeGenModule &CGM, const CXXMethodDecl *MD, + bool IsUnprototyped, bool ForVTable) { + // Always emit thunks in the MS C++ ABI. We cannot rely on other TUs to + // provide thunks for us. + if (CGM.getTarget().getCXXABI().isMicrosoft()) + return true; - // FIXME: re-use FnInfo in this computation. - llvm::Constant *C = CGM.GetAddrOfThunk(GD, Thunk); - llvm::GlobalValue *Entry; + // In the Itanium C++ ABI, vtable thunks are provided by TUs that provide + // definitions of the main method. Therefore, emitting thunks with the vtable + // is purely an optimization. Emit the thunk if optimizations are enabled and + // all of the parameter types are complete. + if (ForVTable) + return CGM.getCodeGenOpts().OptimizationLevel && !IsUnprototyped; - // Strip off a bitcast if we got one back. - if (llvm::ConstantExpr *CE = dyn_cast(C)) { - assert(CE->getOpcode() == llvm::Instruction::BitCast); - Entry = cast(CE->getOperand(0)); - } else { - Entry = cast(C); - } + // Always emit thunks along with the method definition. + return true; +} - // There's already a declaration with the same name, check if it has the same - // type or if we need to replace it. - if (Entry->getType()->getElementType() != - CGM.getTypes().GetFunctionTypeForVTable(GD)) { - llvm::GlobalValue *OldThunkFn = Entry; +llvm::Constant *CodeGenVTables::maybeEmitThunk(GlobalDecl GD, + const ThunkInfo &TI, + bool ForVTable) { + const CXXMethodDecl *MD = cast(GD.getDecl()); - // If the types mismatch then we have to rewrite the definition. - assert(OldThunkFn->isDeclaration() && - "Shouldn't replace non-declaration"); + // First, get a declaration. Compute the mangled name. Don't worry about + // getting the function prototype right, since we may only need this + // declaration to fill in a vtable slot. + SmallString<256> Name; + MangleContext &MCtx = CGM.getCXXABI().getMangleContext(); + llvm::raw_svector_ostream Out(Name); + if (const CXXDestructorDecl *DD = dyn_cast(MD)) + MCtx.mangleCXXDtorThunk(DD, GD.getDtorType(), TI.This, Out); + else + MCtx.mangleThunk(MD, TI, Out); + llvm::Type *ThunkVTableTy = CGM.getTypes().GetFunctionTypeForVTable(GD); + llvm::Constant *Thunk = CGM.GetAddrOfThunk(Name, ThunkVTableTy, GD); + + // If we don't need to emit a definition, return this declaration as is. + bool IsUnprototyped = !CGM.getTypes().isFuncTypeConvertible( + MD->getType()->castAs()); + if (!shouldEmitVTableThunk(CGM, MD, IsUnprototyped, ForVTable)) + return Thunk; + + // Arrange a function prototype appropriate for a function definition. In some + // cases in the MS ABI, we may need to build an unprototyped musttail thunk. + const CGFunctionInfo &FnInfo = + IsUnprototyped ? CGM.getTypes().arrangeUnprototypedMustTailThunk(MD) + : CGM.getTypes().arrangeGlobalDeclaration(GD); + llvm::FunctionType *ThunkFnTy = CGM.getTypes().GetFunctionType(FnInfo); + + // If the type of the underlying GlobalValue is wrong, we'll have to replace + // it. It should be a declaration. + llvm::Function *ThunkFn = cast(Thunk->stripPointerCasts()); + if (ThunkFn->getFunctionType() != ThunkFnTy) { + llvm::GlobalValue *OldThunkFn = ThunkFn; + + assert(OldThunkFn->isDeclaration() && "Shouldn't replace non-declaration"); // Remove the name from the old thunk function and get a new thunk. OldThunkFn->setName(StringRef()); - Entry = cast(CGM.GetAddrOfThunk(GD, Thunk)); + ThunkFn = llvm::Function::Create(ThunkFnTy, llvm::Function::ExternalLinkage, + Name.str(), &CGM.getModule()); + CGM.SetLLVMFunctionAttributes(MD, FnInfo, ThunkFn); // If needed, replace the old thunk with a bitcast. if (!OldThunkFn->use_empty()) { llvm::Constant *NewPtrForOldDecl = - llvm::ConstantExpr::getBitCast(Entry, OldThunkFn->getType()); + llvm::ConstantExpr::getBitCast(ThunkFn, OldThunkFn->getType()); OldThunkFn->replaceAllUsesWith(NewPtrForOldDecl); } @@ -484,61 +524,48 @@ OldThunkFn->eraseFromParent(); } - llvm::Function *ThunkFn = cast(Entry); bool ABIHasKeyFunctions = CGM.getTarget().getCXXABI().hasKeyFunctions(); bool UseAvailableExternallyLinkage = ForVTable && ABIHasKeyFunctions; if (!ThunkFn->isDeclaration()) { if (!ABIHasKeyFunctions || UseAvailableExternallyLinkage) { // There is already a thunk emitted for this function, do nothing. - return; + return ThunkFn; } - setThunkProperties(CGM, Thunk, ThunkFn, ForVTable, GD); - return; + setThunkProperties(CGM, TI, ThunkFn, ForVTable, GD); + return ThunkFn; } + // If this will be unprototyped, add the "thunk" attribute so that LLVM knows + // that the return type is meaningless. These thunks can be used to call + // functions with differing return types, and the caller is required to cast + // the prototype appropriately to extract the correct value. + if (IsUnprototyped) + ThunkFn->addFnAttr("thunk"); + CGM.SetLLVMFunctionAttributesForDefinition(GD.getDecl(), ThunkFn); - if (ThunkFn->isVarArg()) { + if (!IsUnprototyped && ThunkFn->isVarArg()) { // Varargs thunks are special; we can't just generate a call because // we can't copy the varargs. Our implementation is rather // expensive/sucky at the moment, so don't generate the thunk unless // we have to. // FIXME: Do something better here; GenerateVarArgsThunk is extremely ugly. if (UseAvailableExternallyLinkage) - return; - ThunkFn = - CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD, Thunk); + return ThunkFn; + ThunkFn = CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD, + TI); } else { // Normal thunk body generation. - CodeGenFunction(CGM).generateThunk(ThunkFn, FnInfo, GD, Thunk); + CodeGenFunction(CGM).generateThunk(ThunkFn, FnInfo, GD, TI, IsUnprototyped); } - setThunkProperties(CGM, Thunk, ThunkFn, ForVTable, GD); -} - -void CodeGenVTables::maybeEmitThunkForVTable(GlobalDecl GD, - const ThunkInfo &Thunk) { - // If the ABI has key functions, only the TU with the key function should emit - // the thunk. However, we can allow inlining of thunks if we emit them with - // available_externally linkage together with vtables when optimizations are - // enabled. - if (CGM.getTarget().getCXXABI().hasKeyFunctions() && - !CGM.getCodeGenOpts().OptimizationLevel) - return; - - // We can't emit thunks for member functions with incomplete types. - const CXXMethodDecl *MD = cast(GD.getDecl()); - if (!CGM.getTypes().isFuncTypeConvertible( - MD->getType()->castAs())) - return; - - emitThunk(GD, Thunk, /*ForVTable=*/true); + setThunkProperties(CGM, TI, ThunkFn, ForVTable, GD); + return ThunkFn; } -void CodeGenVTables::EmitThunks(GlobalDecl GD) -{ +void CodeGenVTables::EmitThunks(GlobalDecl GD) { const CXXMethodDecl *MD = cast(GD.getDecl())->getCanonicalDecl(); @@ -553,7 +580,7 @@ return; for (const ThunkInfo& Thunk : *ThunkInfoVector) - emitThunk(GD, Thunk, /*ForVTable=*/false); + maybeEmitThunk(GD, Thunk, /*ForVTable=*/false); } void CodeGenVTables::addVTableComponent( @@ -646,9 +673,8 @@ layout.vtable_thunks()[nextVTableThunkIndex].first == idx) { auto &thunkInfo = layout.vtable_thunks()[nextVTableThunkIndex].second; - maybeEmitThunkForVTable(GD, thunkInfo); nextVTableThunkIndex++; - fnPtr = CGM.GetAddrOfThunk(GD, thunkInfo); + fnPtr = maybeEmitThunk(GD, thunkInfo, /*ForVTable=*/true); // Otherwise we can use the method definition directly. } else { Index: clang/lib/CodeGen/CodeGenFunction.h =================================================================== --- clang/lib/CodeGen/CodeGenFunction.h +++ clang/lib/CodeGen/CodeGenFunction.h @@ -1692,10 +1692,10 @@ void FinishFunction(SourceLocation EndLoc=SourceLocation()); void StartThunk(llvm::Function *Fn, GlobalDecl GD, - const CGFunctionInfo &FnInfo); + const CGFunctionInfo &FnInfo, bool IsUnprototyped); - void EmitCallAndReturnForThunk(llvm::Constant *Callee, - const ThunkInfo *Thunk); + void EmitCallAndReturnForThunk(llvm::Constant *Callee, const ThunkInfo *Thunk, + bool IsUnprototyped); void FinishThunk(); @@ -1705,7 +1705,8 @@ /// Generate a thunk for the given method. void generateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo, - GlobalDecl GD, const ThunkInfo &Thunk); + GlobalDecl GD, const ThunkInfo &Thunk, + bool IsUnprototyped); llvm::Function *GenerateVarArgsThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo, Index: clang/lib/CodeGen/CodeGenModule.h =================================================================== --- clang/lib/CodeGen/CodeGenModule.h +++ clang/lib/CodeGen/CodeGenModule.h @@ -800,7 +800,8 @@ ConstantAddress GetAddrOfUuidDescriptor(const CXXUuidofExpr* E); /// Get the address of the thunk for the given global decl. - llvm::Constant *GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk); + llvm::Constant *GetAddrOfThunk(StringRef Name, llvm::Type *FnTy, + GlobalDecl GD); /// Get a reference to the target of VD. ConstantAddress GetWeakRefReference(const ValueDecl *VD); Index: clang/lib/CodeGen/CodeGenTypes.h =================================================================== --- clang/lib/CodeGen/CodeGenTypes.h +++ clang/lib/CodeGen/CodeGenTypes.h @@ -313,7 +313,8 @@ const FunctionProtoType *type, RequiredArgs required, unsigned numPrefixArgs); - const CGFunctionInfo &arrangeMSMemberPointerThunk(const CXXMethodDecl *MD); + const CGFunctionInfo & + arrangeUnprototypedMustTailThunk(const CXXMethodDecl *MD); const CGFunctionInfo &arrangeMSCtorClosure(const CXXConstructorDecl *CD, CXXCtorType CT); const CGFunctionInfo &arrangeCXXMethodType(const CXXRecordDecl *RD, Index: clang/lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1951,7 +1951,8 @@ return cast(GV); // Create the llvm::Function. - const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeMSMemberPointerThunk(MD); + const CGFunctionInfo &FnInfo = + CGM.getTypes().arrangeUnprototypedMustTailThunk(MD); llvm::FunctionType *ThunkTy = CGM.getTypes().GetFunctionType(FnInfo); llvm::Function *ThunkFn = llvm::Function::Create(ThunkTy, llvm::Function::ExternalLinkage, Index: clang/test/CodeGenCXX/ms-thunks-unprototyped-return.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/ms-thunks-unprototyped-return.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -fno-rtti-data -triple x86_64-windows-msvc -emit-llvm-only %s -verify + +// Verify that we error out on this return adjusting thunk that we can't emit. + +struct Incomplete; + +struct A { + virtual A * clone(Incomplete p) = 0; +}; +struct B : virtual A { + // expected-error@+1 2 {{cannot compile this return-adjusting thunk with incomplete parameter type yet}} + B * clone(Incomplete p) override; +}; +struct C : B { int c; }; +C c; Index: clang/test/CodeGenCXX/ms-thunks-unprototyped.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/ms-thunks-unprototyped.cpp @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -fno-rtti-data -triple x86_64-windows-msvc -emit-llvm %s -o - | FileCheck %s + +// In this example, C does not override B::foo, but it needs to emit a thunk to +// adjust for the relative difference of position between A-in-B and A-in-C. + +struct Incomplete; +template +struct DoNotInstantiate { + typename T::does_not_exist field; +}; +template +struct InstantiateLater; + +struct A { + virtual void foo(Incomplete p) = 0; + virtual void bar(DoNotInstantiate p) = 0; + virtual int baz(InstantiateLater p) = 0; +}; +struct B : virtual A { + void foo(Incomplete p) override; + void bar(DoNotInstantiate p) override; + inline int baz(InstantiateLater p) override; +}; +struct C : B { int c; }; +C c; + +// CHECK: @"??_7C@@6B@" = linkonce_odr unnamed_addr constant +// CHECK-SAME: void (%struct.B*, ...)* @"?foo@B@@W7EAAXUIncomplete@@@Z" +// CHECK-SAME: void (%struct.B*, ...)* @"?bar@B@@W7EAAXU?$DoNotInstantiate@H@@@Z" +// CHECK-SAME: i32 (i8*, i32)* @"?baz@B@@W7EAAHU?$InstantiateLater@H@@@Z" + +// The thunks should have a -8 adjustment. + +// CHECK-LABEL: define linkonce_odr dso_local void @"?foo@B@@W7EAAXUIncomplete@@@Z"(%struct.B* %this, ...) +// CHECK: %[[THIS_ADJ_i8:[^ ]*]] = getelementptr i8, i8* {{.*}}, i32 -8 +// CHECK: %[[THIS_ADJ:[^ ]*]] = bitcast i8* %[[THIS_ADJ_i8]] to %struct.B* +// CHECK: musttail call void (%struct.B*, ...) {{.*}}@"?foo@B@@UEAAXUIncomplete@@@Z" +// CHECK-SAME: (%struct.B* %[[THIS_ADJ]], ...) +// CHECK-NEXT: ret void + +// CHECK-LABEL: define linkonce_odr dso_local void @"?bar@B@@W7EAAXU?$DoNotInstantiate@H@@@Z"(%struct.B* %this, ...) +// CHECK: %[[THIS_ADJ_i8:[^ ]*]] = getelementptr i8, i8* {{.*}}, i32 -8 +// CHECK: %[[THIS_ADJ:[^ ]*]] = bitcast i8* %[[THIS_ADJ_i8]] to %struct.B* +// CHECK: musttail call void (%struct.B*, ...) {{.*}}@"?bar@B@@UEAAXU?$DoNotInstantiate@H@@@Z" +// CHECK-SAME: (%struct.B* %[[THIS_ADJ]], ...) +// CHECK-NEXT: ret void + +// If we complete the definition later, things work out. +template struct InstantiateLater { T x; }; +inline int B::baz(InstantiateLater p) { return p.x; } + +// CHECK-LABEL: define linkonce_odr dso_local i32 @"?baz@B@@W7EAAHU?$InstantiateLater@H@@@Z"(i8* %this.coerce, i32 %p.coerce) +// CHECK: = getelementptr i8, i8* {{.*}}, i32 -8 +// CHECK: tail call i32 @"?baz@B@@UEAAHU?$InstantiateLater@H@@@Z"(i8* {{[^,]*}}, i32 {{.*}}) + +// CHECK-LABEL: define linkonce_odr dso_local i32 @"?baz@B@@UEAAHU?$InstantiateLater@H@@@Z"(i8* %this.coerce, i32 %p.coerce)