@@ -2352,126 +2352,26 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2352
2352
D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL));
2353
2353
}
2354
2354
2355
- static void diagnoseInvalidPriority(Sema &S, uint32_t Priority,
2356
- const ParsedAttr &A,
2357
- SourceLocation PriorityLoc) {
2358
- constexpr uint32_t ReservedPriorityLower = 101, ReservedPriorityUpper = 65535;
2359
-
2360
- // Only perform the priority check if the attribute is outside of a system
2361
- // header. Values <= 100 are reserved for the implementation, and libc++
2362
- // benefits from being able to specify values in that range. Values > 65535
2363
- // are reserved for historical reasons.
2364
- if ((Priority < ReservedPriorityLower || Priority > ReservedPriorityUpper) &&
2365
- !S.getSourceManager().isInSystemHeader(A.getLoc())) {
2366
- S.Diag(A.getLoc(), diag::warn_priority_out_of_range)
2367
- << PriorityLoc << A << ReservedPriorityLower << ReservedPriorityUpper;
2368
- }
2369
- }
2370
-
2371
- static bool FunctionParamsAreMainLike(ASTContext &Context,
2372
- const FunctionDecl *FD) {
2373
- assert(FD->hasPrototype() && "expected the function to have a prototype");
2374
- const auto *FPT = FD->getType()->castAs<FunctionProtoType>();
2375
- QualType CharPP =
2376
- Context.getPointerType(Context.getPointerType(Context.CharTy));
2377
- QualType Expected[] = {Context.IntTy, CharPP, CharPP, CharPP};
2378
- for (unsigned I = 0;
2379
- I < sizeof(Expected) / sizeof(QualType) && I < FPT->getNumParams();
2380
- ++I) {
2381
- QualType AT = FPT->getParamType(I);
2382
-
2383
- if (!Context.hasSameUnqualifiedType(AT, Expected[I])) {
2384
- if (Expected[I] == CharPP) {
2385
- // As an extension, the following forms are okay:
2386
- // char const **
2387
- // char const * const *
2388
- // char * const *
2389
-
2390
- QualifierCollector Qs;
2391
- const PointerType *PT;
2392
- if ((PT = Qs.strip(AT)->getAs<PointerType>()) &&
2393
- (PT = Qs.strip(PT->getPointeeType())->getAs<PointerType>()) &&
2394
- Context.hasSameType(QualType(Qs.strip(PT->getPointeeType()), 0),
2395
- Context.CharTy)) {
2396
- Qs.removeConst();
2397
- if (!Qs.empty())
2398
- return false;
2399
- continue; // Accepted as an extension.
2400
- }
2401
- }
2402
- return false;
2403
- }
2404
- }
2405
- return true;
2406
- }
2407
-
2408
- template <typename CtorDtorAttr>
2409
- static void handleCtorDtorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2410
- uint32_t Priority = CtorDtorAttr::DefaultPriority;
2355
+ static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2356
+ uint32_t priority = ConstructorAttr::DefaultPriority;
2411
2357
if (S.getLangOpts().HLSL && AL.getNumArgs()) {
2412
2358
S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported);
2413
2359
return;
2414
2360
}
2361
+ if (AL.getNumArgs() &&
2362
+ !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority))
2363
+ return;
2415
2364
2416
- // If we're given an argument for the priority, check that it's valid.
2417
- if (AL.getNumArgs()) {
2418
- if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Priority))
2419
- return;
2420
-
2421
- // Diagnose an invalid priority, but continue to process the attribute.
2422
- diagnoseInvalidPriority(S, Priority, AL, AL.getArgAsExpr(0)->getExprLoc());
2423
- }
2365
+ D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority));
2366
+ }
2424
2367
2425
- // Ensure the function we're attaching to is something that is sensible to
2426
- // automatically call before or after main(); it should accept no arguments.
2427
- // In theory, a void return type is the only truly safe return type (consider
2428
- // that calling conventions may place returned values in a hidden pointer
2429
- // argument passed to the function that will not be present when called
2430
- // automatically). However, there is a significant amount of existing code
2431
- // which uses an int return type. So we will accept void, int, and
2432
- // unsigned int return types. Any other return type, or a non-void parameter
2433
- // list is treated as an error because it's a form of type system
2434
- // incompatibility. The function also cannot be a member function. We allow
2435
- // K&R C functions because that's a difficult edge case where it depends on
2436
- // how the function is defined as to whether it does or does not expect
2437
- // arguments.
2438
- //
2439
- // However! glibc on ELF will pass the same arguments to a constructor
2440
- // function as are given to main(), so we will allow `int, char *[]` and
2441
- // `int, char *[], char *[]` (or qualified versions thereof), but only if
2442
- // the target is explicitly for glibc.
2443
- const auto *FD = cast<FunctionDecl>(D);
2444
- QualType RetTy = FD->getReturnType();
2445
- bool IsGlibC = S.Context.getTargetInfo().getTriple().isGNUEnvironment();
2446
- if (!(RetTy->isVoidType() ||
2447
- RetTy->isSpecificBuiltinType(BuiltinType::UInt) ||
2448
- RetTy->isSpecificBuiltinType(BuiltinType::Int)) ||
2449
- FD->isVariadic() ||
2450
- (FD->hasPrototype() &&
2451
- ((!IsGlibC && FD->getNumParams() != 0) ||
2452
- (IsGlibC && !FunctionParamsAreMainLike(S.Context, FD))))) {
2453
- S.Diag(AL.getLoc(), diag::err_ctor_dtor_attr_on_non_void_func)
2454
- << AL << FD->getSourceRange();
2455
- return;
2456
- }
2457
- if (FD->getType()->castAs<FunctionType>()->getCallConv() !=
2458
- CallingConv::CC_C) {
2459
- S.Diag(AL.getLoc(), diag::err_ctor_dtor_calling_conv)
2460
- << AL << FD->getSourceRange();
2461
- return;
2462
- }
2463
- if (const auto *MD = dyn_cast<CXXMethodDecl>(FD); MD && MD->isInstance()) {
2464
- S.Diag(AL.getLoc(), diag::err_ctor_dtor_member_func)
2465
- << AL << FD->getSourceRange();
2466
- return;
2467
- }
2468
- if (FD->isConsteval()) {
2469
- S.Diag(AL.getLoc(), diag::err_ctordtor_attr_consteval)
2470
- << AL << FD->getSourceRange();
2368
+ static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
2369
+ uint32_t priority = DestructorAttr::DefaultPriority;
2370
+ if (AL.getNumArgs() &&
2371
+ !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority))
2471
2372
return;
2472
- }
2473
2373
2474
- D->addAttr(CtorDtorAttr::Create (S.Context, Priority , AL));
2374
+ D->addAttr(::new (S.Context) DestructorAttr(S.Context , AL, priority ));
2475
2375
}
2476
2376
2477
2377
template <typename AttrTy>
@@ -3988,9 +3888,16 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3988
3888
return;
3989
3889
}
3990
3890
3991
- // Diagnose an invalid priority, but continue to process the attribute.
3992
- diagnoseInvalidPriority(S, prioritynum, AL, E->getExprLoc());
3993
-
3891
+ // Only perform the priority check if the attribute is outside of a system
3892
+ // header. Values <= 100 are reserved for the implementation, and libc++
3893
+ // benefits from being able to specify values in that range.
3894
+ if ((prioritynum < 101 || prioritynum > 65535) &&
3895
+ !S.getSourceManager().isInSystemHeader(AL.getLoc())) {
3896
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_range)
3897
+ << E->getSourceRange() << AL << 101 << 65535;
3898
+ AL.setInvalid();
3899
+ return;
3900
+ }
3994
3901
D->addAttr(::new (S.Context) InitPriorityAttr(S.Context, AL, prioritynum));
3995
3902
}
3996
3903
@@ -9052,13 +8959,13 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
9052
8959
handlePassObjectSizeAttr(S, D, AL);
9053
8960
break;
9054
8961
case ParsedAttr::AT_Constructor:
9055
- handleCtorDtorAttr<ConstructorAttr> (S, D, AL);
8962
+ handleConstructorAttr (S, D, AL);
9056
8963
break;
9057
8964
case ParsedAttr::AT_Deprecated:
9058
8965
handleDeprecatedAttr(S, D, AL);
9059
8966
break;
9060
8967
case ParsedAttr::AT_Destructor:
9061
- handleCtorDtorAttr<DestructorAttr> (S, D, AL);
8968
+ handleDestructorAttr (S, D, AL);
9062
8969
break;
9063
8970
case ParsedAttr::AT_EnableIf:
9064
8971
handleEnableIfAttr(S, D, AL);
0 commit comments