瀏覽代碼

[opaque pointer types] Fix the CallInfo passed to EmitCall in some
edge cases.

Currently, EmitCall emits a call instruction with a function type
derived from the pointee-type of the callee. This *should* be the same
as the type created from the CallInfo parameter, but in some cases an
incorrect CallInfo was being passed.

All of these fixes were discovered by the addition of the assert in
EmitCall which verifies that the passed-in CallInfo matches the
Callee's function type.

As far as I know, these issues caused no bugs at the moment, as the
correct types were ultimately being emitted. But, some would become
problematic when pointee types are removed.

List of fixes:

* arrangeCXXConstructorCall was passing an incorrect value for the
number of Required args, when calling an inheriting constructor
where the inherited constructor is variadic. (The inheriting
constructor doesn't actually get passed any of the user's args, but
the code was calculating it as if it did).

* arrangeFreeFunctionLikeCall was not including the count of the
pass_object_size arguments in the count of required args.

* OpenCL uses other address spaces for the "this" pointer. However,
commonEmitCXXMemberOrOperatorCall was not annotating the address
space on the "this" argument of the call.

* Destructor calls were being created with EmitCXXMemberOrOperatorCall
instead of EmitCXXDestructorCall in a few places. This was a problem
because the calling convention sometimes has destructors returning
"this" rather than void, and the latter function knows about that,
and sets up the types properly (through calling
arrangeCXXStructorDeclaration), while the former does not.

* generateObjCGetterBody: the 'objc_getProperty' function returns type
'id', but was being called as if it returned the particular
property's type. (That is of course the *dynamic* return type, and
there's a downcast immediately after.)

* OpenMP user-defined reduction functions (#pragma omp declare
reduction) can be called with a subclass of the declared type. In
such case, the call was being setup as if the function had been
actually declared to take the subtype, rather than the base type.

Differential Revision: https://reviews.llvm.org/D57664

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@353181 91177308-0d34-0410-b5e6-96231b3b80d8

James Y Knight 6 年之前
父節點
當前提交
b896b552dd

+ 38 - 15
lib/CodeGen/CGCall.cpp

@@ -67,10 +67,17 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) {
 }
 }
 
 
 /// Derives the 'this' type for codegen purposes, i.e. ignoring method CVR
 /// Derives the 'this' type for codegen purposes, i.e. ignoring method CVR
-/// qualification.
-static CanQualType GetThisType(ASTContext &Context, const CXXRecordDecl *RD,
-                               const CXXMethodDecl *MD) {
-  QualType RecTy = Context.getTagDeclType(RD)->getCanonicalTypeInternal();
+/// qualification. Either or both of RD and MD may be null. A null RD indicates
+/// that there is no meaningful 'this' type, and a null MD can occur when
+/// calling a method pointer.
+CanQualType CodeGenTypes::DeriveThisType(const CXXRecordDecl *RD,
+                                         const CXXMethodDecl *MD) {
+  QualType RecTy;
+  if (RD)
+    RecTy = Context.getTagDeclType(RD)->getCanonicalTypeInternal();
+  else
+    RecTy = Context.VoidTy;
+
   if (MD)
   if (MD)
     RecTy = Context.getAddrSpaceQualType(RecTy, MD->getMethodQualifiers().getAddressSpace());
     RecTy = Context.getAddrSpaceQualType(RecTy, MD->getMethodQualifiers().getAddressSpace());
   return Context.getPointerType(CanQualType::CreateUnsafe(RecTy));
   return Context.getPointerType(CanQualType::CreateUnsafe(RecTy));
@@ -235,7 +242,7 @@ static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) {
 
 
 /// Arrange the argument and result information for a call to an
 /// Arrange the argument and result information for a call to an
 /// unknown C++ non-static member function of the given abstract type.
 /// unknown C++ non-static member function of the given abstract type.
-/// (Zero value of RD means we don't have any meaningful "this" argument type,
+/// (A null RD means we don't have any meaningful "this" argument type,
 ///  so fall back to a generic pointer type).
 ///  so fall back to a generic pointer type).
 /// The member function must be an ordinary function, i.e. not a
 /// The member function must be an ordinary function, i.e. not a
 /// constructor or destructor.
 /// constructor or destructor.
@@ -246,10 +253,7 @@ CodeGenTypes::arrangeCXXMethodType(const CXXRecordDecl *RD,
   SmallVector<CanQualType, 16> argTypes;
   SmallVector<CanQualType, 16> argTypes;
 
 
   // Add the 'this' pointer.
   // Add the 'this' pointer.
-  if (RD)
-    argTypes.push_back(GetThisType(Context, RD, MD));
-  else
-    argTypes.push_back(Context.VoidPtrTy);
+  argTypes.push_back(DeriveThisType(RD, MD));
 
 
   return ::arrangeLLVMFunctionInfo(
   return ::arrangeLLVMFunctionInfo(
       *this, true, argTypes,
       *this, true, argTypes,
@@ -303,7 +307,7 @@ CodeGenTypes::arrangeCXXStructorDeclaration(const CXXMethodDecl *MD,
 
 
   SmallVector<CanQualType, 16> argTypes;
   SmallVector<CanQualType, 16> argTypes;
   SmallVector<FunctionProtoType::ExtParameterInfo, 16> paramInfos;
   SmallVector<FunctionProtoType::ExtParameterInfo, 16> paramInfos;
-  argTypes.push_back(GetThisType(Context, MD->getParent(), MD));
+  argTypes.push_back(DeriveThisType(MD->getParent(), MD));
 
 
   bool PassParams = true;
   bool PassParams = true;
 
 
@@ -403,8 +407,11 @@ CodeGenTypes::arrangeCXXConstructorCall(const CallArgList &args,
   unsigned TotalPrefixArgs = 1 + ExtraPrefixArgs;
   unsigned TotalPrefixArgs = 1 + ExtraPrefixArgs;
 
 
   CanQual<FunctionProtoType> FPT = GetFormalType(D);
   CanQual<FunctionProtoType> FPT = GetFormalType(D);
-  RequiredArgs Required =
-      RequiredArgs::forPrototypePlus(FPT, TotalPrefixArgs + ExtraSuffixArgs);
+  RequiredArgs Required = PassProtoArgs
+                              ? RequiredArgs::forPrototypePlus(
+                                    FPT, TotalPrefixArgs + ExtraSuffixArgs)
+                              : RequiredArgs::All;
+
   GlobalDecl GD(D, CtorKind);
   GlobalDecl GD(D, CtorKind);
   CanQualType ResultType = TheCXXABI.HasThisReturn(GD)
   CanQualType ResultType = TheCXXABI.HasThisReturn(GD)
                                ? ArgTypes.front()
                                ? ArgTypes.front()
@@ -530,7 +537,7 @@ const CGFunctionInfo &
 CodeGenTypes::arrangeUnprototypedMustTailThunk(const CXXMethodDecl *MD) {
 CodeGenTypes::arrangeUnprototypedMustTailThunk(const CXXMethodDecl *MD) {
   assert(MD->isVirtual() && "only methods have thunks");
   assert(MD->isVirtual() && "only methods have thunks");
   CanQual<FunctionProtoType> FTP = GetFormalType(MD);
   CanQual<FunctionProtoType> FTP = GetFormalType(MD);
-  CanQualType ArgTys[] = { GetThisType(Context, MD->getParent(), MD) };
+  CanQualType ArgTys[] = {DeriveThisType(MD->getParent(), MD)};
   return arrangeLLVMFunctionInfo(Context.VoidTy, /*instanceMethod=*/false,
   return arrangeLLVMFunctionInfo(Context.VoidTy, /*instanceMethod=*/false,
                                  /*chainCall=*/false, ArgTys,
                                  /*chainCall=*/false, ArgTys,
                                  FTP->getExtInfo(), {}, RequiredArgs(1));
                                  FTP->getExtInfo(), {}, RequiredArgs(1));
@@ -544,7 +551,7 @@ CodeGenTypes::arrangeMSCtorClosure(const CXXConstructorDecl *CD,
   CanQual<FunctionProtoType> FTP = GetFormalType(CD);
   CanQual<FunctionProtoType> FTP = GetFormalType(CD);
   SmallVector<CanQualType, 2> ArgTys;
   SmallVector<CanQualType, 2> ArgTys;
   const CXXRecordDecl *RD = CD->getParent();
   const CXXRecordDecl *RD = CD->getParent();
-  ArgTys.push_back(GetThisType(Context, RD, CD));
+  ArgTys.push_back(DeriveThisType(RD, CD));
   if (CT == Ctor_CopyingClosure)
   if (CT == Ctor_CopyingClosure)
     ArgTys.push_back(*FTP->param_type_begin());
     ArgTys.push_back(*FTP->param_type_begin());
   if (RD->getNumVBases() > 0)
   if (RD->getNumVBases() > 0)
@@ -577,7 +584,7 @@ arrangeFreeFunctionLikeCall(CodeGenTypes &CGT,
   // extra prefix plus the arguments in the prototype.
   // extra prefix plus the arguments in the prototype.
   if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fnType)) {
   if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fnType)) {
     if (proto->isVariadic())
     if (proto->isVariadic())
-      required = RequiredArgs(proto->getNumParams() + numExtraRequiredArgs);
+      required = RequiredArgs::forPrototypePlus(proto, numExtraRequiredArgs);
 
 
     if (proto->hasExtParameterInfos())
     if (proto->hasExtParameterInfos())
       addExtParameterInfosForCall(paramInfos, proto, numExtraRequiredArgs,
       addExtParameterInfosForCall(paramInfos, proto, numExtraRequiredArgs,
@@ -802,6 +809,8 @@ CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC,
                                        ArrayRef<CanQualType> argTypes,
                                        ArrayRef<CanQualType> argTypes,
                                        RequiredArgs required) {
                                        RequiredArgs required) {
   assert(paramInfos.empty() || paramInfos.size() == argTypes.size());
   assert(paramInfos.empty() || paramInfos.size() == argTypes.size());
+  assert(!required.allowsOptionalArgs() ||
+         required.getNumRequiredArgs() <= argTypes.size());
 
 
   void *buffer =
   void *buffer =
     operator new(totalSizeToAlloc<ArgInfo,             ExtParameterInfo>(
     operator new(totalSizeToAlloc<ArgInfo,             ExtParameterInfo>(
@@ -3818,6 +3827,20 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
 
 
   llvm::FunctionType *IRFuncTy = Callee.getFunctionType();
   llvm::FunctionType *IRFuncTy = Callee.getFunctionType();
 
 
+#ifndef NDEBUG
+  if (!(CallInfo.isVariadic() && CallInfo.getArgStruct())) {
+    // For an inalloca varargs function, we don't expect CallInfo to match the
+    // function pointer's type, because the inalloca struct a will have extra
+    // fields in it for the varargs parameters.  Code later in this function
+    // bitcasts the function pointer to the type derived from CallInfo.
+    //
+    // In other cases, we assert that the types match up (until pointers stop
+    // having pointee types).
+    llvm::FunctionType *IRFuncTyFromInfo = getTypes().GetFunctionType(CallInfo);
+    assert(IRFuncTy == IRFuncTyFromInfo);
+  }
+#endif
+
   // 1. Set up the arguments.
   // 1. Set up the arguments.
 
 
   // If we're using inalloca, insert the allocation after the stack save.
   // If we're using inalloca, insert the allocation after the stack save.

+ 14 - 16
lib/CodeGen/CGExprCXX.cpp

@@ -40,13 +40,11 @@ commonEmitCXXMemberOrOperatorCall(CodeGenFunction &CGF, const CXXMethodDecl *MD,
          isa<CXXOperatorCallExpr>(CE));
          isa<CXXOperatorCallExpr>(CE));
   assert(MD->isInstance() &&
   assert(MD->isInstance() &&
          "Trying to emit a member or operator call expr on a static method!");
          "Trying to emit a member or operator call expr on a static method!");
-  ASTContext &C = CGF.getContext();
 
 
   // Push the this ptr.
   // Push the this ptr.
   const CXXRecordDecl *RD =
   const CXXRecordDecl *RD =
       CGF.CGM.getCXXABI().getThisArgumentTypeForMethod(MD);
       CGF.CGM.getCXXABI().getThisArgumentTypeForMethod(MD);
-  Args.add(RValue::get(This),
-           RD ? C.getPointerType(C.getTypeDeclType(RD)) : C.VoidPtrTy);
+  Args.add(RValue::get(This), CGF.getTypes().DeriveThisType(RD, MD));
 
 
   // If there is an implicit parameter (e.g. VTT), emit it.
   // If there is an implicit parameter (e.g. VTT), emit it.
   if (ImplicitParam) {
   if (ImplicitParam) {
@@ -326,9 +324,6 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
       CallLoc, This.getPointer(), C.getRecordType(CalleeDecl->getParent()),
       CallLoc, This.getPointer(), C.getRecordType(CalleeDecl->getParent()),
       /*Alignment=*/CharUnits::Zero(), SkippedChecks);
       /*Alignment=*/CharUnits::Zero(), SkippedChecks);
 
 
-  // FIXME: Uses of 'MD' past this point need to be audited. We may need to use
-  // 'CalleeDecl' instead.
-
   // C++ [class.virtual]p12:
   // C++ [class.virtual]p12:
   //   Explicit qualification with the scope operator (5.1) suppresses the
   //   Explicit qualification with the scope operator (5.1) suppresses the
   //   virtual call mechanism.
   //   virtual call mechanism.
@@ -337,7 +332,7 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
   // because then we know what the type is.
   // because then we know what the type is.
   bool UseVirtualCall = CanUseVirtualCall && !DevirtualizedMethod;
   bool UseVirtualCall = CanUseVirtualCall && !DevirtualizedMethod;
 
 
-  if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) {
+  if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(CalleeDecl)) {
     assert(CE->arg_begin() == CE->arg_end() &&
     assert(CE->arg_begin() == CE->arg_end() &&
            "Destructor shouldn't have explicit parameters");
            "Destructor shouldn't have explicit parameters");
     assert(ReturnValue.isNull() && "Destructor shouldn't have return value");
     assert(ReturnValue.isNull() && "Destructor shouldn't have return value");
@@ -347,26 +342,29 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
           cast<CXXMemberCallExpr>(CE));
           cast<CXXMemberCallExpr>(CE));
     } else {
     } else {
       CGCallee Callee;
       CGCallee Callee;
-      if (getLangOpts().AppleKext && MD->isVirtual() && HasQualifier)
-        Callee = BuildAppleKextVirtualCall(MD, Qualifier, Ty);
+      if (getLangOpts().AppleKext && Dtor->isVirtual() && HasQualifier)
+        Callee = BuildAppleKextVirtualCall(Dtor, Qualifier, Ty);
       else if (!DevirtualizedMethod)
       else if (!DevirtualizedMethod)
         Callee = CGCallee::forDirect(
         Callee = CGCallee::forDirect(
             CGM.getAddrOfCXXStructor(Dtor, StructorType::Complete, FInfo, Ty),
             CGM.getAddrOfCXXStructor(Dtor, StructorType::Complete, FInfo, Ty),
             GlobalDecl(Dtor, Dtor_Complete));
             GlobalDecl(Dtor, Dtor_Complete));
       else {
       else {
-        const CXXDestructorDecl *DDtor =
-          cast<CXXDestructorDecl>(DevirtualizedMethod);
         Callee = CGCallee::forDirect(
         Callee = CGCallee::forDirect(
-            CGM.GetAddrOfFunction(GlobalDecl(DDtor, Dtor_Complete), Ty),
-            GlobalDecl(DDtor, Dtor_Complete));
+            CGM.GetAddrOfFunction(GlobalDecl(Dtor, Dtor_Complete), Ty),
+            GlobalDecl(Dtor, Dtor_Complete));
       }
       }
-      EmitCXXMemberOrOperatorCall(
-          CalleeDecl, Callee, ReturnValue, This.getPointer(),
-          /*ImplicitParam=*/nullptr, QualType(), CE, nullptr);
+
+      EmitCXXDestructorCall(Dtor, Callee, This.getPointer(),
+                            /*ImplicitParam=*/nullptr,
+                            /*ImplicitParamTy=*/QualType(), nullptr,
+                            getFromDtorType(Dtor_Complete));
     }
     }
     return RValue::get(nullptr);
     return RValue::get(nullptr);
   }
   }
 
 
+  // FIXME: Uses of 'MD' past this point need to be audited. We may need to use
+  // 'CalleeDecl' instead.
+
   CGCallee Callee;
   CGCallee Callee;
   if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
   if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
     Callee = CGCallee::forDirect(
     Callee = CGCallee::forDirect(

+ 3 - 3
lib/CodeGen/CGObjC.cpp

@@ -1051,9 +1051,9 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
     // FIXME: We shouldn't need to get the function info here, the
     // FIXME: We shouldn't need to get the function info here, the
     // runtime already should have computed it to build the function.
     // runtime already should have computed it to build the function.
     llvm::CallBase *CallInstruction;
     llvm::CallBase *CallInstruction;
-    RValue RV = EmitCall(
-        getTypes().arrangeBuiltinFunctionCall(propType, args),
-        callee, ReturnValueSlot(), args, &CallInstruction);
+    RValue RV = EmitCall(getTypes().arrangeBuiltinFunctionCall(
+                             getContext().getObjCIdType(), args),
+                         callee, ReturnValueSlot(), args, &CallInstruction);
     if (llvm::CallInst *call = dyn_cast<llvm::CallInst>(CallInstruction))
     if (llvm::CallInst *call = dyn_cast<llvm::CallInst>(CallInstruction))
       call->setTailCall();
       call->setTailCall();
 
 

+ 4 - 0
lib/CodeGen/CodeGenTypes.h

@@ -182,6 +182,10 @@ public:
   /// Convert clang calling convention to LLVM callilng convention.
   /// Convert clang calling convention to LLVM callilng convention.
   unsigned ClangCallConvToLLVMCallConv(CallingConv CC);
   unsigned ClangCallConvToLLVMCallConv(CallingConv CC);
 
 
+  /// Derives the 'this' type for codegen purposes, i.e. ignoring method CVR
+  /// qualification.
+  CanQualType DeriveThisType(const CXXRecordDecl *RD, const CXXMethodDecl *MD);
+
   /// ConvertType - Convert type T into a llvm::Type.
   /// ConvertType - Convert type T into a llvm::Type.
   llvm::Type *ConvertType(QualType T);
   llvm::Type *ConvertType(QualType T);
 
 

+ 4 - 6
lib/CodeGen/ItaniumCXXABI.cpp

@@ -1566,9 +1566,8 @@ void ItaniumCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
     Callee = CGCallee::forDirect(
     Callee = CGCallee::forDirect(
         CGM.getAddrOfCXXStructor(DD, getFromDtorType(Type)), GD);
         CGM.getAddrOfCXXStructor(DD, getFromDtorType(Type)), GD);
 
 
-  CGF.EmitCXXMemberOrOperatorCall(DD, Callee, ReturnValueSlot(),
-                                  This.getPointer(), VTT, VTTTy,
-                                  nullptr, nullptr);
+  CGF.EmitCXXDestructorCall(DD, Callee, This.getPointer(), VTT, VTTTy, nullptr,
+                            getFromDtorType(Type));
 }
 }
 
 
 void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
 void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
@@ -1766,9 +1765,8 @@ llvm::Value *ItaniumCXXABI::EmitVirtualDestructorCall(
   CGCallee Callee =
   CGCallee Callee =
       CGCallee::forVirtual(CE, GlobalDecl(Dtor, DtorType), This, Ty);
       CGCallee::forVirtual(CE, GlobalDecl(Dtor, DtorType), This, Ty);
 
 
-  CGF.EmitCXXMemberOrOperatorCall(Dtor, Callee, ReturnValueSlot(),
-                                  This.getPointer(), /*ImplicitParam=*/nullptr,
-                                  QualType(), CE, nullptr);
+  CGF.EmitCXXDestructorCall(Dtor, Callee, This.getPointer(), nullptr,
+                            QualType(), nullptr, getFromDtorType(DtorType));
   return nullptr;
   return nullptr;
 }
 }
 
 

+ 4 - 2
lib/Sema/SemaOpenMP.cpp

@@ -10747,7 +10747,8 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
               return D;
               return D;
             return nullptr;
             return nullptr;
           }))
           }))
-    return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc);
+    return SemaRef.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(),
+                                    VK_LValue, Loc);
   if (auto *VD = filterLookupForUDR<ValueDecl *>(
   if (auto *VD = filterLookupForUDR<ValueDecl *>(
           Lookups, [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * {
           Lookups, [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * {
             if (!D->isInvalidDecl() &&
             if (!D->isInvalidDecl() &&
@@ -10765,7 +10766,8 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
                                          /*DiagID=*/0) !=
                                          /*DiagID=*/0) !=
             Sema::AR_inaccessible) {
             Sema::AR_inaccessible) {
           SemaRef.BuildBasePathArray(Paths, BasePath);
           SemaRef.BuildBasePathArray(Paths, BasePath);
-          return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc);
+          return SemaRef.BuildDeclRefExpr(
+              VD, VD->getType().getNonReferenceType(), VK_LValue, Loc);
         }
         }
       }
       }
     }
     }

+ 1 - 3
test/CodeGenObjC/getter-property-mismatch.m

@@ -15,6 +15,4 @@
 
 
 // CHECK:  [[CALL:%.*]] = tail call i8* @objc_getProperty
 // CHECK:  [[CALL:%.*]] = tail call i8* @objc_getProperty
 // CHECK:  [[ONE:%.*]] = bitcast i8* [[CALL:%.*]] to [[T1:%.*]]*
 // CHECK:  [[ONE:%.*]] = bitcast i8* [[CALL:%.*]] to [[T1:%.*]]*
-// CHECK:  [[TWO:%.*]] = bitcast [[T1]]* [[ONE]] to [[T2:%.*]]*
-// CHECK:  ret [[T2]]* [[TWO]]
-
+// CHECK:  ret [[T1]]* [[ONE]]