================ @@ -2352,26 +2352,78 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL)); } -static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - uint32_t priority = ConstructorAttr::DefaultPriority; +static bool diagnoseInvalidPriority(Sema &S, uint32_t Priority, + const ParsedAttr &A, + SourceLocation PriorityLoc) { + constexpr uint32_t ReservedPriorityLower = 101, ReservedPriorityUpper = 65535; + + // Only perform the priority check if the attribute is outside of a system + // header. Values <= 100 are reserved for the implementation, and libc++ + // benefits from being able to specify values in that range. Values > 65535 + // are reserved for historical reasons. + if ((Priority < ReservedPriorityLower || Priority > ReservedPriorityUpper) && + !S.getSourceManager().isInSystemHeader(A.getLoc())) { + S.Diag(A.getLoc(), diag::err_attribute_argument_out_of_range) + << PriorityLoc << A << ReservedPriorityLower << ReservedPriorityUpper; + A.setInvalid(); + return true; + } + return false; +} + +template <typename CtorDtorAttr> +static void handleCtorDtorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + uint32_t Priority = CtorDtorAttr::DefaultPriority; if (S.getLangOpts().HLSL && AL.getNumArgs()) { S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported); return; } - if (AL.getNumArgs() && - !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority)) - return; - D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority)); -} + // If we're given an argument for the priority, check that it's valid. + if (AL.getNumArgs()) { + if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Priority)) + return; -static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - uint32_t priority = DestructorAttr::DefaultPriority; - if (AL.getNumArgs() && - !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority)) + // Ensure the priority is in a reasonable range. + if (diagnoseInvalidPriority(S, Priority, AL, + AL.getArgAsExpr(0)->getExprLoc())) + return; + } + + // Ensure the function we're attaching to is something that is sensible to + // automatically call before or after main(); it should accept no arguments. + // In theory, a void return type is the only truly safe return type (consider + // that calling conventions may place returned values in a hidden pointer + // argument passed to the function that will not be present when called + // automatically). However, there is a significant amount of existing code + // which uses an int return type. So we will accept void, int, and + // unsigned int return types. Any other return type, or a non-void parameter + // list is treated as an error because it's a form of type system + // incompatibility. The function also cannot be a member function. We allow + // K&R C functions because that's a difficult edge case where it depends on + // how the function is defined as to whether it does or does not expect + // arguments. + const auto *FD = cast<FunctionDecl>(D); + QualType RetTy = FD->getReturnType(); + if (!(RetTy->isVoidType() || ---------------- AaronBallman wrote:
Yeah, I think those restrictions make sense, good call! https://github.com/llvm/llvm-project/pull/67360 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits