diff options
| author | Mingming Liu <mingmingl@google.com> | 2025-09-10 15:25:31 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-10 15:25:31 -0700 |
| commit | 1417dafa1db9cb1b2b09438aa9f53ea5ab6e36e2 (patch) | |
| tree | 57f4b1f313c8cf74eed8819870f39c36ea263c68 /clang/lib/Sema/SemaDeclAttr.cpp | |
| parent | 898b813bc8a6d0276bf0f4769f5f2f64b34e632d (diff) | |
| parent | b8cefcb601ddaa18482555c4ff363c01a270c2fe (diff) | |
Merge branch 'main' into users/mingmingl-llvm/samplefdo-profile-formatusers/mingmingl-llvm/samplefdo-profile-format
Diffstat (limited to 'clang/lib/Sema/SemaDeclAttr.cpp')
| -rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 100 |
1 files changed, 59 insertions, 41 deletions
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 3685bcefbf76..cb2c132cca97 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" @@ -58,6 +59,7 @@ #include "clang/Sema/SemaSwift.h" #include "clang/Sema/SemaWasm.h" #include "clang/Sema/SemaX86.h" +#include "llvm/ADT/APSInt.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Demangle/Demangle.h" @@ -169,7 +171,7 @@ static bool isIntOrBool(Expr *Exp) { // Check to see if the type is a smart pointer of some kind. We assume // it's a smart pointer if it defines both operator-> and operator*. -static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) { +static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordDecl *Record) { auto IsOverloadedOperatorPresent = [&S](const RecordDecl *Record, OverloadedOperatorKind Op) { DeclContextLookupResult Result = @@ -177,7 +179,6 @@ static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) { return !Result.empty(); }; - const RecordDecl *Record = RT->getOriginalDecl()->getDefinitionOrSelf(); bool foundStarOperator = IsOverloadedOperatorPresent(Record, OO_Star); bool foundArrowOperator = IsOverloadedOperatorPresent(Record, OO_Arrow); if (foundStarOperator && foundArrowOperator) @@ -212,14 +213,14 @@ static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D, if (QT->isAnyPointerType()) return true; - if (const auto *RT = QT->getAs<RecordType>()) { + if (const auto *RD = QT->getAsRecordDecl()) { // If it's an incomplete type, it could be a smart pointer; skip it. // (We don't want to force template instantiation if we can avoid it, // since that would alter the order in which templates are instantiated.) - if (RT->isIncompleteType()) + if (!RD->isCompleteDefinition()) return true; - if (threadSafetyCheckIsSmartPointer(S, RT)) + if (threadSafetyCheckIsSmartPointer(S, RD)) return true; } @@ -229,13 +230,13 @@ static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D, /// Checks that the passed in QualType either is of RecordType or points /// to RecordType. Returns the relevant RecordType, null if it does not exit. -static const RecordType *getRecordType(QualType QT) { - if (const auto *RT = QT->getAs<RecordType>()) - return RT; +static const RecordDecl *getRecordDecl(QualType QT) { + if (const auto *RD = QT->getAsRecordDecl()) + return RD; - // Now check if we point to record type. - if (const auto *PT = QT->getAs<PointerType>()) - return PT->getPointeeType()->getAs<RecordType>(); + // Now check if we point to a record. + if (const auto *PT = QT->getAsCanonical<PointerType>()) + return PT->getPointeeType()->getAsRecordDecl(); return nullptr; } @@ -257,36 +258,34 @@ static bool checkRecordDeclForAttr(const RecordDecl *RD) { } static bool checkRecordTypeForCapability(Sema &S, QualType Ty) { - const RecordType *RT = getRecordType(Ty); + const auto *RD = getRecordDecl(Ty); - if (!RT) + if (!RD) return false; // Don't check for the capability if the class hasn't been defined yet. - if (RT->isIncompleteType()) + if (!RD->isCompleteDefinition()) return true; // Allow smart pointers to be used as capability objects. // FIXME -- Check the type that the smart pointer points to. - if (threadSafetyCheckIsSmartPointer(S, RT)) + if (threadSafetyCheckIsSmartPointer(S, RD)) return true; - return checkRecordDeclForAttr<CapabilityAttr>( - RT->getOriginalDecl()->getDefinitionOrSelf()); + return checkRecordDeclForAttr<CapabilityAttr>(RD); } static bool checkRecordTypeForScopedCapability(Sema &S, QualType Ty) { - const RecordType *RT = getRecordType(Ty); + const auto *RD = getRecordDecl(Ty); - if (!RT) + if (!RD) return false; // Don't check for the capability if the class hasn't been defined yet. - if (RT->isIncompleteType()) + if (!RD->isCompleteDefinition()) return true; - return checkRecordDeclForAttr<ScopedLockableAttr>( - RT->getOriginalDecl()->getDefinitionOrSelf()); + return checkRecordDeclForAttr<ScopedLockableAttr>(RD); } static bool checkTypedefTypeForCapability(QualType Ty) { @@ -401,10 +400,10 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, ArgTy = DRE->getDecl()->getType(); // First see if we can just cast to record type, or pointer to record type. - const RecordType *RT = getRecordType(ArgTy); + const auto *RD = getRecordDecl(ArgTy); // Now check if we index into a record type function param. - if(!RT && ParamIdxOk) { + if (!RD && ParamIdxOk) { const auto *FD = dyn_cast<FunctionDecl>(D); const auto *IL = dyn_cast<IntegerLiteral>(ArgExp); if(FD && IL) { @@ -2159,29 +2158,51 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL)); } +static ExprResult sharedGetConstructorDestructorAttrExpr(Sema &S, + const ParsedAttr &AL) { + // If no Expr node exists on the attribute, return a nullptr result (default + // priority to be used). If Expr node exists but is not valid, return an + // invalid result. Otherwise, return the Expr. + Expr *E = nullptr; + if (AL.getNumArgs() == 1) { + E = AL.getArgAsExpr(0); + if (E->isValueDependent()) { + if (!E->isTypeDependent() && !E->getType()->isIntegerType()) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIntegerConstant << E->getSourceRange(); + return ExprError(); + } + } else { + uint32_t priority; + if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority)) { + return ExprError(); + } + return ConstantExpr::Create(S.Context, E, + APValue(llvm::APSInt::getUnsigned(priority))); + } + } + return E; +} + static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - uint32_t priority = ConstructorAttr::DefaultPriority; if (S.getLangOpts().HLSL && AL.getNumArgs()) { S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported); return; } - if (AL.getNumArgs() && - !S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority)) + ExprResult E = sharedGetConstructorDestructorAttrExpr(S, AL); + if (E.isInvalid()) return; S.Diag(D->getLocation(), diag::warn_global_constructor) << D->getSourceRange(); - - D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority)); + D->addAttr(ConstructorAttr::Create(S.Context, E.get(), AL)); } static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - uint32_t priority = DestructorAttr::DefaultPriority; - if (AL.getNumArgs() && - !S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority)) + ExprResult E = sharedGetConstructorDestructorAttrExpr(S, AL); + if (E.isInvalid()) return; S.Diag(D->getLocation(), diag::warn_global_destructor) << D->getSourceRange(); - - D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority)); + D->addAttr(DestructorAttr::Create(S.Context, E.get(), AL)); } template <typename AttrTy> @@ -3639,7 +3660,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { QualType T = cast<VarDecl>(D)->getType(); if (S.Context.getAsArrayType(T)) T = S.Context.getBaseElementType(T); - if (!T->getAs<RecordType>()) { + if (!T->isRecordType()) { S.Diag(AL.getLoc(), diag::err_init_priority_object_attr); AL.setInvalid(); return; @@ -4163,10 +4184,7 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { RecordDecl *RD = nullptr; const auto *TD = dyn_cast<TypedefNameDecl>(D); if (TD && TD->getUnderlyingType()->isUnionType()) - RD = TD->getUnderlyingType() - ->getAsUnionType() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + RD = TD->getUnderlyingType()->getAsRecordDecl(); else RD = dyn_cast<RecordDecl>(D); @@ -4739,14 +4757,14 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI, // GCC allows 'mode' attribute on enumeration types (even incomplete), except // for vector modes. So, 'enum X __attribute__((mode(QI)));' forms a complete // type, 'enum { A } __attribute__((mode(V4SI)))' is rejected. - if ((isa<EnumDecl>(D) || OldElemTy->getAs<EnumType>()) && + if ((isa<EnumDecl>(D) || OldElemTy->isEnumeralType()) && VectorSize.getBoolValue()) { Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << CI.getRange(); return; } bool IntegralOrAnyEnumType = (OldElemTy->isIntegralOrEnumerationType() && !OldElemTy->isBitIntType()) || - OldElemTy->getAs<EnumType>(); + OldElemTy->isEnumeralType(); if (!OldElemTy->getAs<BuiltinType>() && !OldElemTy->isComplexType() && !IntegralOrAnyEnumType) |
