]> granicus.if.org Git - clang/commitdiff
Represent pass_object_size attrs in ExtParameterInfo
authorGeorge Burgess IV <george.burgess.iv@gmail.com>
Fri, 24 Feb 2017 02:49:47 +0000 (02:49 +0000)
committerGeorge Burgess IV <george.burgess.iv@gmail.com>
Fri, 24 Feb 2017 02:49:47 +0000 (02:49 +0000)
The goal of this is to fix a bug in modules where we'd merge
FunctionDecls that differed in their pass_object_size attributes. Since
we can overload on the presence of pass_object_size attributes, this
behavior is incorrect.

We don't represent `N` in `pass_object_size(N)` as part of
ExtParameterInfo, since it's an error to overload solely on the value of
N. This means that we have a bug if we have two modules that declare
functions that differ only in their pass_object_size attrs, like so:

// In module A, from a.h
void foo(char *__attribute__((pass_object_size(0))));

// In module B, from b.h
void foo(char *__attribute__((pass_object_size(1))));

// In module C, in main.c
#include "a.h"
#include "b.h"

At the moment, we'll merge the foo decls, when we should instead emit a
diagnostic about an invalid overload. We seem to have similar (silent)
behavior if we overload only on the return type of `foo` instead; I'll
try to find a good place to put a FIXME (or I'll just file a bug) soon.

This patch also fixes a bug where we'd not output the proper extended
parameter info for declarations with pass_object_size attrs.

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

include/clang/AST/Type.h
lib/CodeGen/CGCall.cpp
lib/Sema/SemaType.cpp
lib/Serialization/ASTReaderDecl.cpp
test/CodeGenObjCXX/arc-attrs-abi.mm
test/Modules/Inputs/overloadable-attrs/a.h
test/Modules/overloadable-attrs.cpp

index f88d0435b296ca35fc9fe6d8dba3b47a83287f97..9c1d11006752cc1bb867644904cd7df8cedbcb1a 100644 (file)
@@ -3116,9 +3116,11 @@ public:
   class ExtParameterInfo {
     enum {
       ABIMask         = 0x0F,
-      IsConsumed      = 0x10
+      IsConsumed      = 0x10,
+      HasPassObjSize  = 0x20,
     };
     unsigned char Data;
+
   public:
     ExtParameterInfo() : Data(0) {}
 
@@ -3147,6 +3149,15 @@ public:
       return copy;
     }
 
+    bool hasPassObjectSize() const {
+      return Data & HasPassObjSize;
+    }
+    ExtParameterInfo withHasPassObjectSize() const {
+      ExtParameterInfo Copy = *this;
+      Copy.Data |= HasPassObjSize;
+      return Copy;
+    }
+
     unsigned char getOpaqueValue() const { return Data; }
     static ExtParameterInfo getFromOpaqueValue(unsigned char data) {
       ExtParameterInfo result;
index 428098da263c697835eacc3da4c22e78a4eadffd..e389e4224ed875099281c66b0f4b0a260f7c33c3 100644 (file)
@@ -101,39 +101,64 @@ CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> FTNP) {
                                  FTNP->getExtInfo(), {}, RequiredArgs(0));
 }
 
-/// Adds the formal parameters in FPT to the given prefix. If any parameter in
+static void addExtParameterInfosForCall(
+         llvm::SmallVectorImpl<FunctionProtoType::ExtParameterInfo> &paramInfos,
+                                        const FunctionProtoType *proto,
+                                        unsigned prefixArgs,
+                                        unsigned totalArgs) {
+  assert(proto->hasExtParameterInfos());
+  assert(paramInfos.size() <= prefixArgs);
+  assert(proto->getNumParams() + prefixArgs <= totalArgs);
+
+  paramInfos.reserve(totalArgs);
+
+  // Add default infos for any prefix args that don't already have infos.
+  paramInfos.resize(prefixArgs);
+
+  // Add infos for the prototype.
+  for (const auto &ParamInfo : proto->getExtParameterInfos()) {
+    paramInfos.push_back(ParamInfo);
+    // pass_object_size params have no parameter info.
+    if (ParamInfo.hasPassObjectSize())
+      paramInfos.emplace_back();
+  }
+
+  assert(paramInfos.size() <= totalArgs &&
+         "Did we forget to insert pass_object_size args?");
+  // Add default infos for the variadic and/or suffix arguments.
+  paramInfos.resize(totalArgs);
+}
+
+/// Adds the formal paramaters in FPT to the given prefix. If any parameter in
 /// FPT has pass_object_size attrs, then we'll add parameters for those, too.
 static void appendParameterTypes(const CodeGenTypes &CGT,
                                  SmallVectorImpl<CanQualType> &prefix,
               SmallVectorImpl<FunctionProtoType::ExtParameterInfo> &paramInfos,
-                                 CanQual<FunctionProtoType> FPT,
-                                 const FunctionDecl *FD) {
-  // Fill out paramInfos.
-  if (FPT->hasExtParameterInfos() || !paramInfos.empty()) {
-    assert(paramInfos.size() <= prefix.size());
-    auto protoParamInfos = FPT->getExtParameterInfos();
-    paramInfos.reserve(prefix.size() + protoParamInfos.size());
-    paramInfos.resize(prefix.size());
-    paramInfos.append(protoParamInfos.begin(), protoParamInfos.end());
-  }
-
-  // Fast path: unknown target.
-  if (FD == nullptr) {
+                                 CanQual<FunctionProtoType> FPT) {
+  // Fast path: don't touch param info if we don't need to.
+  if (!FPT->hasExtParameterInfos()) {
+    assert(paramInfos.empty() &&
+           "We have paramInfos, but the prototype doesn't?");
     prefix.append(FPT->param_type_begin(), FPT->param_type_end());
     return;
   }
 
-  // In the vast majority cases, we'll have precisely FPT->getNumParams()
+  unsigned PrefixSize = prefix.size();
+  // In the vast majority of cases, we'll have precisely FPT->getNumParams()
   // parameters; the only thing that can change this is the presence of
   // pass_object_size. So, we preallocate for the common case.
   prefix.reserve(prefix.size() + FPT->getNumParams());
 
-  assert(FD->getNumParams() == FPT->getNumParams());
+  auto ExtInfos = FPT->getExtParameterInfos();
+  assert(ExtInfos.size() == FPT->getNumParams());
   for (unsigned I = 0, E = FPT->getNumParams(); I != E; ++I) {
     prefix.push_back(FPT->getParamType(I));
-    if (FD->getParamDecl(I)->hasAttr<PassObjectSizeAttr>())
+    if (ExtInfos[I].hasPassObjectSize())
       prefix.push_back(CGT.getContext().getSizeType());
   }
+
+  addExtParameterInfosForCall(paramInfos, FPT.getTypePtr(), PrefixSize,
+                              prefix.size());
 }
 
 /// Arrange the LLVM function layout for a value of the given function
@@ -147,7 +172,7 @@ arrangeLLVMFunctionInfo(CodeGenTypes &CGT, bool instanceMethod,
   RequiredArgs Required =
       RequiredArgs::forPrototypePlus(FTP, prefix.size(), FD);
   // FIXME: Kill copy.
-  appendParameterTypes(CGT, prefix, paramInfos, FTP, FD);
+  appendParameterTypes(CGT, prefix, paramInfos, FTP);
   CanQualType resultType = FTP->getReturnType().getUnqualifiedType();
 
   return CGT.arrangeLLVMFunctionInfo(resultType, instanceMethod,
@@ -286,7 +311,7 @@ CodeGenTypes::arrangeCXXStructorDeclaration(const CXXMethodDecl *MD,
 
   // Add the formal parameters.
   if (PassParams)
-    appendParameterTypes(*this, argTypes, paramInfos, FTP, MD);
+    appendParameterTypes(*this, argTypes, paramInfos, FTP);
 
   CGCXXABI::AddedStructorArgs AddedArgs =
       TheCXXABI.buildStructorSignature(MD, Type, argTypes);
@@ -331,26 +356,6 @@ getArgTypesForDeclaration(ASTContext &ctx, const FunctionArgList &args) {
   return argTypes;
 }
 
-static void addExtParameterInfosForCall(
-         llvm::SmallVectorImpl<FunctionProtoType::ExtParameterInfo> &paramInfos,
-                                        const FunctionProtoType *proto,
-                                        unsigned prefixArgs,
-                                        unsigned totalArgs) {
-  assert(proto->hasExtParameterInfos());
-  assert(paramInfos.size() <= prefixArgs);
-  assert(proto->getNumParams() + prefixArgs <= totalArgs);
-
-  // Add default infos for any prefix args that don't already have infos.
-  paramInfos.resize(prefixArgs);
-
-  // Add infos for the prototype.
-  auto protoInfos = proto->getExtParameterInfos();
-  paramInfos.append(protoInfos.begin(), protoInfos.end());
-
-  // Add default infos for the variadic arguments.
-  paramInfos.resize(totalArgs);
-}
-
 static llvm::SmallVector<FunctionProtoType::ExtParameterInfo, 16>
 getExtParameterInfosForCall(const FunctionProtoType *proto,
                             unsigned prefixArgs, unsigned totalArgs) {
index 6300aa6f1a6ef9fdbe5a2391b173edc3c78699ff..4fe0cf337ffb578c3461db9cdf27279e59963239 100644 (file)
@@ -4488,6 +4488,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
             HasAnyInterestingExtParameterInfos = true;
           }
 
+          if (Param->hasAttr<PassObjectSizeAttr>()) {
+            ExtParameterInfos[i] = ExtParameterInfos[i].withHasPassObjectSize();
+            HasAnyInterestingExtParameterInfos = true;
+          }
+
           ParamTys.push_back(ParamTy);
         }
 
index 0f43e9fcf643b9b511e26b3349c51eccf0b4e05c..7971c30b488fb5d287f0f708a501dcb3924a7cf1 100644 (file)
@@ -2664,9 +2664,12 @@ static bool isSameTemplateParameterList(const TemplateParameterList *X,
 }
 
 /// Determine whether the attributes we can overload on are identical for A and
-/// B. Expects A and B to (otherwise) have the same type.
+/// B. Will ignore any overloadable attrs represented in the type of A and B.
 static bool hasSameOverloadableAttrs(const FunctionDecl *A,
                                      const FunctionDecl *B) {
+  // Note that pass_object_size attributes are represented in the function's
+  // ExtParameterInfo, so we don't need to check them here.
+
   SmallVector<const EnableIfAttr *, 4> AEnableIfs;
   // Since this is an equality check, we can ignore that enable_if attrs show up
   // in reverse order.
@@ -2696,8 +2699,6 @@ static bool hasSameOverloadableAttrs(const FunctionDecl *A,
       return false;
   }
 
-  // FIXME: This doesn't currently consider pass_object_size attributes, since
-  // we aren't guaranteed that A and B have valid parameter lists yet.
   return true;
 }
 
index 22ef7a55d338034cc297b7dd640cb2808c5dc5f9..14bdf8be30e597f6ab29f628389413bf013ebaf4 100644 (file)
@@ -5,14 +5,15 @@
 // caused assertions to fire. Hence, minimal CHECKs.
 
 struct VirtualBase {
-  VirtualBase(__attribute__((ns_consumed)) id x);
+  VirtualBase(__attribute__((ns_consumed)) id x,
+              void * __attribute__((pass_object_size(0))));
 };
 struct WithVirtualBase : virtual VirtualBase {
   WithVirtualBase(__attribute__((ns_consumed)) id x);
 };
 
 WithVirtualBase::WithVirtualBase(__attribute__((ns_consumed)) id x)
-    : VirtualBase(x) {}
+    : VirtualBase(x, (void *)0) {}
 
 
 struct VirtualBase2 {
index e7dabfbe586cc4b54784ea489ceab464e6f4b300..1af769dad315647c11a5710c6226fcb9e2926772 100644 (file)
@@ -14,3 +14,15 @@ constexpr int fn4(int i) __attribute__((enable_if(i, ""))) { return 1; }
 constexpr int fn5(int i) __attribute__((enable_if(i, ""))) { return 1; }
 constexpr int fn5(int i) { return 0; }
 }
+
+namespace pass_object_size_attrs {
+constexpr int fn1(void *const a __attribute__((pass_object_size(0)))) {
+  return 1;
+}
+constexpr int fn1(void *const a) { return 0; }
+
+constexpr int fn2(void *const a) { return 0; }
+constexpr int fn2(void *const a __attribute__((pass_object_size(0)))) {
+  return 1;
+}
+}
index ae9bd73f99f8bf12fab2843ae8776b2902a7df64..38c9558fe8821d8d6374fbe68f09f53fb072c807 100644 (file)
@@ -17,3 +17,6 @@ static_assert(enable_if_attrs::fn4(0) == 0, "");
 static_assert(enable_if_attrs::fn4(1) == 1, "");
 static_assert(enable_if_attrs::fn5(0) == 0, "");
 static_assert(enable_if_attrs::fn5(1) == 1, "");
+
+static_assert(pass_object_size_attrs::fn1(nullptr) == 1, "");
+static_assert(pass_object_size_attrs::fn2(nullptr) == 1, "");