Index: clang/include/clang/AST/Attr.h =================================================================== --- clang/include/clang/AST/Attr.h +++ clang/include/clang/AST/Attr.h @@ -345,6 +345,24 @@ DiagnosticsEngine::ak_attr); return PD; } + +/// Quick wrapper around either a pass_object_size or pass_dynamic_object_size +/// attribute. These have a very similar interface, but are still distinct +/// attributes. +struct PassObjectSizeInfo { + Attr *TheAttr; + int Type; + bool IsDynamic; +}; + +inline Optional +getPassObjectSizeInfo(const ParmVarDecl *PVD) { + if (auto *POS = PVD->getAttr()) + return PassObjectSizeInfo{POS, POS->getType(), false}; + else if (auto *PDOS = PVD->getAttr()) + return PassObjectSizeInfo{PDOS, PDOS->getType(), true}; + return None; +} } // end namespace clang #endif Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -1566,6 +1566,13 @@ let Documentation = [PassObjectSizeDocs]; } +def PassDynamicObjectSize : InheritableParamAttr { + let Spellings = [Clang<"pass_dynamic_object_size">]; + let Args = [IntArgument<"Type">]; + let Subjects = SubjectList<[ParmVar]>; + let Documentation = [PassObjectSizeDocs]; +} + def FortifyStdLib : InheritableAttr { let Spellings = [Clang<"fortify_stdlib">]; let Args = [IntArgument<"Type">, IntArgument<"Flag">]; Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -698,6 +698,15 @@ * It is an error to apply the ``pass_object_size`` attribute to parameters that are not pointers. Additionally, any parameter that ``pass_object_size`` is applied to must be marked ``const`` at its function's definition. + +Clang also supports the ``pass_dynamic_object_size`` attribute, which behaves +identically to ``pass_object_size``, but evaluates a call to +``__builtin_dynamic_object_size`` at the callee instead of +``__builtin_object_size``. ``__builtin_dynamic_object_size`` provides some extra +runtime checks when the object size can't be determined at compile-time. You can +read more about ``__builtin_dynamic_object_size`` `here +`_. + }]; } Index: clang/lib/AST/ItaniumMangle.cpp =================================================================== --- clang/lib/AST/ItaniumMangle.cpp +++ clang/lib/AST/ItaniumMangle.cpp @@ -2830,10 +2830,16 @@ mangleType(Context.getASTContext().getSignatureParameterType(ParamTy)); if (FD) { - if (auto *Attr = FD->getParamDecl(I)->getAttr()) { - // Attr can only take 1 character, so we can hardcode the length below. - assert(Attr->getType() <= 9 && Attr->getType() >= 0); - Out << "U17pass_object_size" << Attr->getType(); + // FIXME: It would be nice to move this before the type, so it conforms to + // the production: + // ::= U # vendor extended type qualifier + const ParmVarDecl *PVD = FD->getParamDecl(I); + if (auto *POS = PVD->getAttr()) { + assert(POS->getType() <= 9 && POS->getType() >= 0); + Out << "U17pass_object_size" << POS->getType(); + } else if (auto *PDOS = PVD->getAttr()) { + assert(PDOS->getType() <= 9 && PDOS->getType() >= 0); + Out << "U25pass_dynamic_object_size" << PDOS->getType(); } } } Index: clang/lib/AST/MicrosoftMangle.cpp =================================================================== --- clang/lib/AST/MicrosoftMangle.cpp +++ clang/lib/AST/MicrosoftMangle.cpp @@ -267,7 +267,7 @@ typedef llvm::DenseMap ArgBackRefMap; ArgBackRefMap TypeBackReferences; - typedef std::set PassObjectSizeArgsSet; + typedef std::set> PassObjectSizeArgsSet; PassObjectSizeArgsSet PassObjectSizeArgs; ASTContext &getASTContext() const { return Context.getASTContext(); } @@ -344,7 +344,7 @@ void mangleObjCMethodName(const ObjCMethodDecl *MD); void mangleArgumentType(QualType T, SourceRange Range); - void manglePassObjectSizeArg(const PassObjectSizeAttr *POSA); + void manglePassObjectSizeArg(PassObjectSizeInfo Info); bool isArtificialTagType(QualType T) const; @@ -1758,17 +1758,16 @@ } } -void MicrosoftCXXNameMangler::manglePassObjectSizeArg( - const PassObjectSizeAttr *POSA) { - int Type = POSA->getType(); - - auto Iter = PassObjectSizeArgs.insert(Type).first; +void MicrosoftCXXNameMangler::manglePassObjectSizeArg(PassObjectSizeInfo Info) { + auto Iter = PassObjectSizeArgs.insert({Info.Type, Info.IsDynamic}).first; auto *TypePtr = (const void *)&*Iter; ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr); if (Found == TypeBackReferences.end()) { - mangleArtificialTagType(TTK_Enum, "__pass_object_size" + llvm::utostr(Type), - {"__clang"}); + std::string Name = + Info.IsDynamic ? "__pass_dynamic_object_size" : "__pass_object_size"; + mangleArtificialTagType(TTK_Enum, Name + llvm::utostr(Info.Type), + {"__clang"}); if (TypeBackReferences.size() < 10) { size_t Size = TypeBackReferences.size(); @@ -2254,9 +2253,11 @@ // FIXME: Is there a defined extension notation for the MS ABI, or is it // necessary to just cross our fingers and hope this type+namespace // combination doesn't conflict with anything? - if (D) - if (const auto *P = D->getParamDecl(I)->getAttr()) - manglePassObjectSizeArg(P); + if (D) { + const ParmVarDecl *PVD = D->getParamDecl(I); + if (Optional Info = getPassObjectSizeInfo(PVD)) + manglePassObjectSizeArg(*Info); + } } // ::= Z # ellipsis if (Proto->isVariadic()) Index: clang/lib/CodeGen/CGBuiltin.cpp =================================================================== --- clang/lib/CodeGen/CGBuiltin.cpp +++ clang/lib/CodeGen/CGBuiltin.cpp @@ -518,19 +518,19 @@ // We need to reference an argument if the pointer is a parameter with the // pass_object_size attribute. if (auto *D = dyn_cast(E->IgnoreParenImpCasts())) { - auto *Param = dyn_cast(D->getDecl()); - auto *PS = D->getDecl()->getAttr(); - if (Param != nullptr && PS != nullptr && - areBOSTypesCompatible(PS->getType(), Type)) { - auto Iter = SizeArguments.find(Param); - assert(Iter != SizeArguments.end()); - - const ImplicitParamDecl *D = Iter->second; - auto DIter = LocalDeclMap.find(D); - assert(DIter != LocalDeclMap.end()); - - return EmitLoadOfScalar(DIter->second, /*volatile=*/false, - getContext().getSizeType(), E->getBeginLoc()); + if (auto *Param = dyn_cast(D->getDecl())) { + Optional Info = getPassObjectSizeInfo(Param); + if (Info && areBOSTypesCompatible(Info->Type, Type)) { + auto Iter = SizeArguments.find(Param); + assert(Iter != SizeArguments.end()); + + const ImplicitParamDecl *D = Iter->second; + auto DIter = LocalDeclMap.find(D); + assert(DIter != LocalDeclMap.end()); + + return EmitLoadOfScalar(DIter->second, /*volatile=*/false, + getContext().getSizeType(), E->getBeginLoc()); + } } } Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -3442,17 +3442,19 @@ RValue EmittedArg) { if (!AC.hasFunctionDecl() || I >= AC.getNumParams()) return; - auto *PS = AC.getParamDecl(I)->getAttr(); - if (PS == nullptr) + + Optional Info = + getPassObjectSizeInfo(AC.getParamDecl(I)); + if (!Info) return; const auto &Context = getContext(); auto SizeTy = Context.getSizeType(); auto T = Builder.getIntNTy(Context.getTypeSize(SizeTy)); assert(EmittedArg.getScalarVal() && "We emitted nothing for the arg?"); - llvm::Value *V = evaluateOrEmitBuiltinObjectSize(Arg, PS->getType(), T, + llvm::Value *V = evaluateOrEmitBuiltinObjectSize(Arg, Info->Type, T, EmittedArg.getScalarVal(), - /*IsDynamic=*/false); + Info->IsDynamic); Args.add(RValue::get(V), SizeTy); // If we're emitting args in reverse, be sure to do so with // pass_object_size, as well. Index: clang/lib/CodeGen/CGClass.cpp =================================================================== --- clang/lib/CodeGen/CGClass.cpp +++ clang/lib/CodeGen/CGClass.cpp @@ -2188,7 +2188,7 @@ EmitDelegateCallArg(Args, Param, E->getLocation()); // Forward __attribute__(pass_object_size). - if (Param->hasAttr()) { + if (getPassObjectSizeInfo(Param) != None) { auto *POSParam = SizeArguments[Param]; assert(POSParam && "missing pass_object_size value for forwarding"); EmitDelegateCallArg(Args, POSParam, E->getLocation()); Index: clang/lib/CodeGen/CGExpr.cpp =================================================================== --- clang/lib/CodeGen/CGExpr.cpp +++ clang/lib/CodeGen/CGExpr.cpp @@ -898,13 +898,12 @@ if (!ParamDecl) return nullptr; - auto *POSAttr = ParamDecl->getAttr(); - if (!POSAttr) + Optional Info = getPassObjectSizeInfo(ParamDecl); + if (!Info) return nullptr; // Don't load the size if it's a lower bound. - int POSType = POSAttr->getType(); - if (POSType != 0 && POSType != 1) + if (Info->Type != 0 && Info->Type != 1) return nullptr; // Find the implicit size parameter. Index: clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenFunction.cpp +++ clang/lib/CodeGen/CodeGenFunction.cpp @@ -1273,7 +1273,7 @@ if (PassedParams) { for (auto *Param : FD->parameters()) { Args.push_back(Param); - if (!Param->hasAttr()) + if (getPassObjectSizeInfo(Param) == None) continue; auto *Implicit = ImplicitParamDecl::Create( Index: clang/lib/Sema/SemaChecking.cpp =================================================================== --- clang/lib/Sema/SemaChecking.cpp +++ clang/lib/Sema/SemaChecking.cpp @@ -12272,10 +12272,10 @@ // constant at function definitions. Because we lack information about // whether we're on a declaration or definition when we're instantiating the // attribute, we need to check for constness here. - if (const auto *Attr = Param->getAttr()) + if (Optional Info = getPassObjectSizeInfo(Param)) if (!Param->getType().isConstQualified()) Diag(Param->getLocation(), diag::err_attribute_pointers_only) - << Attr->getSpelling() << 1; + << Info->TheAttr->getSpelling() << 1; // Check for parameter names shadowing fields from the class. if (LangOpts.CPlusPlus && !Param->isInvalidDecl()) { Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -2931,11 +2931,12 @@ assert(A->getNumParams() == B->getNumParams()); auto AttrEq = [](const ParmVarDecl *A, const ParmVarDecl *B) { - const auto *AttrA = A->getAttr(); - const auto *AttrB = B->getAttr(); - if (AttrA == AttrB) - return true; - return AttrA && AttrB && AttrA->getType() == AttrB->getType(); + Optional InfoA = getPassObjectSizeInfo(A); + Optional InfoB = getPassObjectSizeInfo(B); + if (!InfoA || !InfoB) + return !InfoA && !InfoB; + return std::tie(InfoA->Type, InfoA->IsDynamic) == + std::tie(InfoB->Type, InfoB->IsDynamic); }; return std::equal(A->param_begin(), A->param_end(), B->param_begin(), AttrEq); Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -1104,9 +1104,13 @@ cast(D), AL.getAttributeSpellingListIndex())); } -static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (D->hasAttr()) { - S.Diag(D->getBeginLoc(), diag::err_attribute_only_once_per_parameter) << AL; +static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL, + bool IsDynamic) { + assert(isa(D) && "Should be checked already!"); + auto *PVD = cast(D); + if (getPassObjectSizeInfo(PVD) != None) { + S.Diag(PVD->getBeginLoc(), diag::err_attribute_only_once_per_parameter) + << AL; return; } @@ -1128,13 +1132,20 @@ // kindness to users, we allow the parameter to be non-const for declarations. // At this point, we have no clue if `D` belongs to a function declaration or // definition, so we defer the constness check until later. - if (!cast(D)->getType()->isPointerType()) { + if (!PVD->getType()->isPointerType()) { S.Diag(D->getBeginLoc(), diag::err_attribute_pointers_only) << AL << 1; return; } - D->addAttr(::new (S.Context) PassObjectSizeAttr( - AL.getRange(), S.Context, (int)Type, AL.getAttributeSpellingListIndex())); + if (IsDynamic) { + D->addAttr(::new (S.Context) PassDynamicObjectSizeAttr( + AL.getRange(), S.Context, (int)Type, + AL.getAttributeSpellingListIndex())); + } else { + D->addAttr(::new (S.Context) + PassObjectSizeAttr(AL.getRange(), S.Context, (int)Type, + AL.getAttributeSpellingListIndex())); + } } static void handleConsumableAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -6722,7 +6733,10 @@ handleConstantAttr(S, D, AL); break; case ParsedAttr::AT_PassObjectSize: - handlePassObjectSizeAttr(S, D, AL); + handlePassObjectSizeAttr(S, D, AL, false); + break; + case ParsedAttr::AT_PassDynamicObjectSize: + handlePassObjectSizeAttr(S, D, AL, true); break; case ParsedAttr::AT_Constructor: handleConstructorAttr(S, D, AL); Index: clang/lib/Sema/SemaLambda.cpp =================================================================== --- clang/lib/Sema/SemaLambda.cpp +++ clang/lib/Sema/SemaLambda.cpp @@ -1213,7 +1213,7 @@ // This conversion is explicitly disabled if the lambda's function has // pass_object_size attributes on any of its parameters. auto HasPassObjectSizeAttr = [](const ParmVarDecl *P) { - return P->hasAttr(); + return getPassObjectSizeInfo(P) != None; }; if (llvm::any_of(CallOperator->parameters(), HasPassObjectSizeAttr)) return; Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -40,7 +40,7 @@ static bool functionHasPassObjectSizeParams(const FunctionDecl *FD) { return llvm::any_of(FD->parameters(), [](const ParmVarDecl *P) { - return P->hasAttr(); + return getPassObjectSizeInfo(P) != None; }); } @@ -9583,7 +9583,7 @@ } auto I = llvm::find_if(FD->parameters(), [](const ParmVarDecl *P) { - return P->hasAttr(); + return getPassObjectSizeInfo(P) != None; }); if (I == FD->param_end()) return true; Index: clang/lib/Sema/SemaType.cpp =================================================================== --- clang/lib/Sema/SemaType.cpp +++ clang/lib/Sema/SemaType.cpp @@ -4804,7 +4804,7 @@ HasAnyInterestingExtParameterInfos = true; } - if (Param->hasAttr()) { + if (getPassObjectSizeInfo(Param) != None) { ExtParameterInfos[i] = ExtParameterInfos[i].withHasPassObjectSize(); HasAnyInterestingExtParameterInfos = true; } Index: clang/test/CodeGen/pass-object-size.c =================================================================== --- clang/test/CodeGen/pass-object-size.c +++ clang/test/CodeGen/pass-object-size.c @@ -7,6 +7,7 @@ }; #define PS(N) __attribute__((pass_object_size(N))) +#define PDS(N) __attribute__((pass_dynamic_object_size(N))) int gi = 0; @@ -16,26 +17,52 @@ return __builtin_object_size(p, 0); } +// CHECK-LABEL: define i32 @DynamicObjectSize0(i8* %{{.*}}, i64) +int DynamicObjectSize0(void *const p PDS(0)) { + // CHECK-NOT: @llvm.objectsize + return __builtin_dynamic_object_size(p, 0); +} + // CHECK-LABEL: define i32 @ObjectSize1(i8* %{{.*}}, i64) int ObjectSize1(void *const p PS(1)) { // CHECK-NOT: @llvm.objectsize return __builtin_object_size(p, 1); } +// CHECK-LABEL: define i32 @DynamicObjectSize1(i8* %{{.*}}, i64) +int DynamicObjectSize1(void *const p PDS(1)) { + // CHECK-NOT: @llvm.objectsize + return __builtin_dynamic_object_size(p, 1); +} + // CHECK-LABEL: define i32 @ObjectSize2(i8* %{{.*}}, i64) int ObjectSize2(void *const p PS(2)) { // CHECK-NOT: @llvm.objectsize return __builtin_object_size(p, 2); } +// CHECK-LABEL: define i32 @DynamicObjectSize2(i8* %{{.*}}, i64) +int DynamicObjectSize2(void *const p PDS(2)) { + // CHECK-NOT: @llvm.objectsize + return __builtin_object_size(p, 2); +} + // CHECK-LABEL: define i32 @ObjectSize3(i8* %{{.*}}, i64) int ObjectSize3(void *const p PS(3)) { // CHECK-NOT: @llvm.objectsize return __builtin_object_size(p, 3); } +// CHECK-LABEL: define i32 @DynamicObjectSize3(i8* %{{.*}}, i64) +int DynamicObjectSize3(void *const p PDS(3)) { + // CHECK-NOT: @llvm.objectsize + return __builtin_object_size(p, 3); +} + +void *malloc(unsigned long) __attribute__((alloc_size(1))); + // CHECK-LABEL: define void @test1 -void test1() { +void test1(unsigned long sz) { struct Foo t[10]; // CHECK: call i32 @ObjectSize0(i8* %{{.*}}, i64 360) @@ -55,6 +82,21 @@ gi = ObjectSize2(&t[1].t[1]); // CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 36) gi = ObjectSize3(&t[1].t[1]); + + char *ptr = (char *)malloc(sz); + + // CHECK: [[REG:%.*]] = call i64 @llvm.objectsize.i64.p0i8({{.*}}, i1 false, i1 true, i1 true) + // CHECK: call i32 @DynamicObjectSize0(i8* %{{.*}}, i64 [[REG]]) + gi = DynamicObjectSize0(ptr); + + // CHECK: [[WITH_OFFSET:%.*]] = getelementptr + // CHECK: [[REG:%.*]] = call i64 @llvm.objectsize.i64.p0i8(i8* [[WITH_OFFSET]], i1 false, i1 true, i1 true) + // CHECK: call i32 @DynamicObjectSize0(i8* {{.*}}, i64 [[REG]]) + gi = DynamicObjectSize0(ptr+10); + + // CHECK: [[REG:%.*]] = call i64 @llvm.objectsize.i64.p0i8({{.*}}, i1 true, i1 true, i1 true) + // CHECK: call i32 @DynamicObjectSize2(i8* {{.*}}, i64 [[REG]]) + gi = DynamicObjectSize2(ptr); } // CHECK-LABEL: define void @test2 @@ -72,6 +114,13 @@ return __builtin_object_size(p, 0); } +// CHECK-LABEL: define i32 @_Z34NoViableOverloadDynamicObjectSize0Pv +int NoViableOverloadDynamicObjectSize0(void *const p) + __attribute__((overloadable)) { + // CHECK: @llvm.objectsize + return __builtin_object_size(p, 0); +} + // CHECK-LABEL: define i32 @_Z27NoViableOverloadObjectSize1Pv int NoViableOverloadObjectSize1(void *const p) __attribute__((overloadable)) { // CHECK: @llvm.objectsize @@ -97,6 +146,11 @@ return __builtin_object_size(p, 0); } +int NoViableOverloadDynamicObjectSize0(void *const p PDS(0)) + __attribute__((overloadable)) { + return __builtin_dynamic_object_size(p, 0); +} + int NoViableOverloadObjectSize1(void *const p PS(1)) __attribute__((overloadable)) { return __builtin_object_size(p, 1); @@ -154,6 +208,9 @@ gi = NoViableOverloadObjectSize2(&t[1].t[1]); // CHECK: call i32 @_Z27NoViableOverloadObjectSize3PvU17pass_object_size3(i8* %{{.*}}, i64 36) gi = NoViableOverloadObjectSize3(&t[1].t[1]); + + // CHECK: call i32 @_Z34NoViableOverloadDynamicObjectSize0PvU25pass_dynamic_object_size0(i8* %{{.*}}, i64 360) + gi = NoViableOverloadDynamicObjectSize0(&t[1]); } // CHECK-LABEL: define void @test4 @@ -183,6 +240,9 @@ int (*f)(void *) = &NoViableOverloadObjectSize0; gi = f(&t[1]); + + int (*g)(void *) = &NoViableOverloadDynamicObjectSize0; + gi = g(&t[1]); } // CHECK-LABEL: define i32 @IndirectObjectSize0 @@ -213,6 +273,12 @@ return ObjectSize3(p); } +int IndirectDynamicObjectSize0(void *const p PDS(0)) { + // CHECK: call i32 @ObjectSize0(i8* %{{.*}}, i64 %{{.*}}) + // CHECK-NOT: @llvm.objectsize + return ObjectSize0(p); +} + int Overload0(void *, size_t, void *, size_t); int OverloadNoSize(void *, void *); @@ -418,3 +484,10 @@ // CHECK: call i32 @ObjectSize0(i8* [[PTR]] ObjectSize0(C + ({ int a = 65535; a; })); } + +// CHECK-LABEL: define void @test18 +void test18(char *const p PDS(0)) { + // CHECK-NOT: llvm.objectsize + gi = __builtin_dynamic_object_size(p, 0); + gi = __builtin_object_size(p, 0); +} Index: clang/test/CodeGenCXX/mangle-ms.cpp =================================================================== --- clang/test/CodeGenCXX/mangle-ms.cpp +++ clang/test/CodeGenCXX/mangle-ms.cpp @@ -457,6 +457,8 @@ int qux(int *const i __attribute__((pass_object_size(1))), int *const j __attribute__((pass_object_size(0)))) { return 0; } // CHECK-DAG: define dso_local i32 @"?zot@PassObjectSize@@YAHQAHW4__pass_object_size1@__clang@@01@Z" int zot(int *const i __attribute__((pass_object_size(1))), int *const j __attribute__((pass_object_size(1)))) { return 0; } +// CHECK-DAG: define dso_local i32 @"?silly_word@PassObjectSize@@YAHQAHW4__pass_dynamic_object_size1@__clang@@@Z" +int silly_word(int *const i __attribute__((pass_dynamic_object_size(1)))) { return 0; } } namespace Atomic { Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test =================================================================== --- clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -117,6 +117,7 @@ // CHECK-NEXT: OptimizeNone (SubjectMatchRule_function, SubjectMatchRule_objc_method) // CHECK-NEXT: Overloadable (SubjectMatchRule_function) // CHECK-NEXT: ParamTypestate (SubjectMatchRule_variable_is_parameter) +// CHECK-NEXT: PassDynamicObjectSize (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: PassObjectSize (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: RenderScriptKernel (SubjectMatchRule_function) // CHECK-NEXT: ReqdWorkGroupSize (SubjectMatchRule_function) Index: clang/test/Sema/pass-object-size.c =================================================================== --- clang/test/Sema/pass-object-size.c +++ clang/test/Sema/pass-object-size.c @@ -17,6 +17,9 @@ void i(char *p __attribute__((pass_object_size(0)))); // OK -- const is only necessary on definitions, not decls. void j(char *p __attribute__((pass_object_size(0), pass_object_size(1)))); //expected-error{{'pass_object_size' attribute can only be applied once per parameter}} +void k(char *p __attribute__((pass_dynamic_object_size))); // expected-error {{'pass_dynamic_object_size' attribute takes one argument}} +void l(int p __attribute__((pass_dynamic_object_size(0)))); // expected-error {{'pass_dynamic_object_size' attribute only applies to constant pointer arguments}} + #define PS(N) __attribute__((pass_object_size(N))) #define overloaded __attribute__((overloadable)) void Overloaded(void *p PS(0)) overloaded; //expected-note{{previous declaration is here}} @@ -32,14 +35,17 @@ void TakeFnOvl(void (*)(int *)) overloaded; void NotOverloaded(void *p PS(0)); -void IsOverloaded(void *p PS(0)) overloaded; -void IsOverloaded(char *p) overloaded; // char* inestead of void* is intentional +void IsOverloaded(void *p PS(0)) overloaded; // expected-note 2 {{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} + +// char* inestead of void* is intentional +void IsOverloaded(char *p) overloaded; // expected-note{{passing argument to parameter 'p' here}} expected-note 2 {{type mismatch}} + void FunctionPtrs() { void (*p)(void *) = NotOverloaded; //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}} void (*p2)(void *) = &NotOverloaded; //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}} - void (*p3)(void *) = IsOverloaded; //expected-warning{{incompatible pointer types initializing 'void (*)(void *)' with an expression of type ''}} expected-note@-6{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note@-5{{type mismatch}} - void (*p4)(void *) = &IsOverloaded; //expected-warning{{incompatible pointer types initializing 'void (*)(void *)' with an expression of type ''}} expected-note@-7{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note@-6{{type mismatch}} + void (*p3)(void *) = IsOverloaded; //expected-warning{{incompatible pointer types initializing 'void (*)(void *)' with an expression of type ''}} + void (*p4)(void *) = &IsOverloaded; //expected-warning{{incompatible pointer types initializing 'void (*)(void *)' with an expression of type ''}} void (*p5)(char *) = IsOverloaded; void (*p6)(char *) = &IsOverloaded; @@ -52,5 +58,11 @@ int P; (&NotOverloaded)(&P); //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}} - (&IsOverloaded)(&P); //expected-warning{{incompatible pointer types passing 'int *' to parameter of type 'char *'}} expected-note@36{{passing argument to parameter 'p' here}} + (&IsOverloaded)(&P); //expected-warning{{incompatible pointer types passing 'int *' to parameter of type 'char *'}} } + +void mismatch(void *p __attribute__((pass_object_size(0)))); // expected-note {{previous declaration is here}} +void mismatch(void *p __attribute__((pass_dynamic_object_size(0)))); // expected-error {{conflicting pass_object_size attributes on parameters}} + +void mismatch2(void *p __attribute__((pass_dynamic_object_size(0)))); // expected-note {{previous declaration is here}} +void mismatch2(void *p __attribute__((pass_dynamic_object_size(1)))); // expected-error {{conflicting pass_object_size attributes on parameters}}