@@ -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