aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Sema/SemaDeclAttr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaDeclAttr.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Sema/SemaDeclAttr.cpp3794
1 files changed, 519 insertions, 3275 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaDeclAttr.cpp b/contrib/llvm-project/clang/lib/Sema/SemaDeclAttr.cpp
index 6f462de4be78..e2eada24f9fc 100644
--- a/contrib/llvm-project/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/contrib/llvm-project/clang/lib/Sema/SemaDeclAttr.cpp
@@ -26,12 +26,14 @@
#include "clang/Basic/Cuda.h"
#include "clang/Basic/DarwinSDKInfo.h"
#include "clang/Basic/HLSLRuntime.h"
+#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Attr.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Initialization.h"
@@ -39,14 +41,34 @@
#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaAMDGPU.h"
+#include "clang/Sema/SemaARM.h"
+#include "clang/Sema/SemaAVR.h"
+#include "clang/Sema/SemaBPF.h"
+#include "clang/Sema/SemaCUDA.h"
+#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/SemaM68k.h"
+#include "clang/Sema/SemaMIPS.h"
+#include "clang/Sema/SemaMSP430.h"
+#include "clang/Sema/SemaObjC.h"
+#include "clang/Sema/SemaOpenCL.h"
+#include "clang/Sema/SemaOpenMP.h"
+#include "clang/Sema/SemaRISCV.h"
+#include "clang/Sema/SemaSYCL.h"
+#include "clang/Sema/SemaSwift.h"
+#include "clang/Sema/SemaWasm.h"
+#include "clang/Sema/SemaX86.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Demangle/Demangle.h"
#include "llvm/IR/Assumptions.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Triple.h"
#include <optional>
using namespace clang;
@@ -60,192 +82,12 @@ namespace AttributeLangSupport {
};
} // end namespace AttributeLangSupport
-//===----------------------------------------------------------------------===//
-// Helper functions
-//===----------------------------------------------------------------------===//
-
-/// isFunctionOrMethod - Return true if the given decl has function
-/// type (function or function-typed variable) or an Objective-C
-/// method.
-static bool isFunctionOrMethod(const Decl *D) {
- return (D->getFunctionType() != nullptr) || isa<ObjCMethodDecl>(D);
-}
-
-/// Return true if the given decl has function type (function or
-/// function-typed variable) or an Objective-C method or a block.
-static bool isFunctionOrMethodOrBlock(const Decl *D) {
- return isFunctionOrMethod(D) || isa<BlockDecl>(D);
-}
-
-/// Return true if the given decl has a declarator that should have
-/// been processed by Sema::GetTypeForDeclarator.
-static bool hasDeclarator(const Decl *D) {
- // In some sense, TypedefDecl really *ought* to be a DeclaratorDecl.
- return isa<DeclaratorDecl>(D) || isa<BlockDecl>(D) || isa<TypedefNameDecl>(D) ||
- isa<ObjCPropertyDecl>(D);
-}
-
-/// hasFunctionProto - Return true if the given decl has a argument
-/// information. This decl should have already passed
-/// isFunctionOrMethod or isFunctionOrMethodOrBlock.
-static bool hasFunctionProto(const Decl *D) {
- if (const FunctionType *FnTy = D->getFunctionType())
- return isa<FunctionProtoType>(FnTy);
- return isa<ObjCMethodDecl>(D) || isa<BlockDecl>(D);
-}
-
-/// getFunctionOrMethodNumParams - Return number of function or method
-/// parameters. It is an error to call this on a K&R function (use
-/// hasFunctionProto first).
-static unsigned getFunctionOrMethodNumParams(const Decl *D) {
- if (const FunctionType *FnTy = D->getFunctionType())
- return cast<FunctionProtoType>(FnTy)->getNumParams();
- if (const auto *BD = dyn_cast<BlockDecl>(D))
- return BD->getNumParams();
- return cast<ObjCMethodDecl>(D)->param_size();
-}
-
-static const ParmVarDecl *getFunctionOrMethodParam(const Decl *D,
- unsigned Idx) {
- if (const auto *FD = dyn_cast<FunctionDecl>(D))
- return FD->getParamDecl(Idx);
- if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
- return MD->getParamDecl(Idx);
- if (const auto *BD = dyn_cast<BlockDecl>(D))
- return BD->getParamDecl(Idx);
- return nullptr;
-}
-
-static QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) {
- if (const FunctionType *FnTy = D->getFunctionType())
- return cast<FunctionProtoType>(FnTy)->getParamType(Idx);
- if (const auto *BD = dyn_cast<BlockDecl>(D))
- return BD->getParamDecl(Idx)->getType();
-
- return cast<ObjCMethodDecl>(D)->parameters()[Idx]->getType();
-}
-
-static SourceRange getFunctionOrMethodParamRange(const Decl *D, unsigned Idx) {
- if (auto *PVD = getFunctionOrMethodParam(D, Idx))
- return PVD->getSourceRange();
- return SourceRange();
-}
-
-static QualType getFunctionOrMethodResultType(const Decl *D) {
- if (const FunctionType *FnTy = D->getFunctionType())
- return FnTy->getReturnType();
- return cast<ObjCMethodDecl>(D)->getReturnType();
-}
-
-static SourceRange getFunctionOrMethodResultSourceRange(const Decl *D) {
- if (const auto *FD = dyn_cast<FunctionDecl>(D))
- return FD->getReturnTypeSourceRange();
- if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
- return MD->getReturnTypeSourceRange();
- return SourceRange();
-}
-
-static bool isFunctionOrMethodVariadic(const Decl *D) {
- if (const FunctionType *FnTy = D->getFunctionType())
- return cast<FunctionProtoType>(FnTy)->isVariadic();
- if (const auto *BD = dyn_cast<BlockDecl>(D))
- return BD->isVariadic();
- return cast<ObjCMethodDecl>(D)->isVariadic();
-}
-
-static bool isInstanceMethod(const Decl *D) {
- if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(D))
- return MethodDecl->isInstance();
- return false;
-}
-
-static inline bool isNSStringType(QualType T, ASTContext &Ctx,
- bool AllowNSAttributedString = false) {
- const auto *PT = T->getAs<ObjCObjectPointerType>();
- if (!PT)
- return false;
-
- ObjCInterfaceDecl *Cls = PT->getObjectType()->getInterface();
- if (!Cls)
- return false;
-
- IdentifierInfo* ClsName = Cls->getIdentifier();
-
- if (AllowNSAttributedString &&
- ClsName == &Ctx.Idents.get("NSAttributedString"))
- return true;
- // FIXME: Should we walk the chain of classes?
- return ClsName == &Ctx.Idents.get("NSString") ||
- ClsName == &Ctx.Idents.get("NSMutableString");
-}
-
-static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
- const auto *PT = T->getAs<PointerType>();
- if (!PT)
- return false;
-
- const auto *RT = PT->getPointeeType()->getAs<RecordType>();
- if (!RT)
- return false;
-
- const RecordDecl *RD = RT->getDecl();
- if (RD->getTagKind() != TagTypeKind::Struct)
- return false;
-
- return RD->getIdentifier() == &Ctx.Idents.get("__CFString");
-}
-
static unsigned getNumAttributeArgs(const ParsedAttr &AL) {
// FIXME: Include the type in the argument list.
return AL.getNumArgs() + AL.hasParsedType();
}
-/// A helper function to provide Attribute Location for the Attr types
-/// AND the ParsedAttr.
-template <typename AttrInfo>
-static std::enable_if_t<std::is_base_of_v<Attr, AttrInfo>, SourceLocation>
-getAttrLoc(const AttrInfo &AL) {
- return AL.getLocation();
-}
-static SourceLocation getAttrLoc(const ParsedAttr &AL) { return AL.getLoc(); }
-
-/// If Expr is a valid integer constant, get the value of the integer
-/// expression and return success or failure. May output an error.
-///
-/// Negative argument is implicitly converted to unsigned, unless
-/// \p StrictlyUnsigned is true.
-template <typename AttrInfo>
-static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr,
- uint32_t &Val, unsigned Idx = UINT_MAX,
- bool StrictlyUnsigned = false) {
- std::optional<llvm::APSInt> I = llvm::APSInt(32);
- if (Expr->isTypeDependent() ||
- !(I = Expr->getIntegerConstantExpr(S.Context))) {
- if (Idx != UINT_MAX)
- S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type)
- << &AI << Idx << AANT_ArgumentIntegerConstant
- << Expr->getSourceRange();
- else
- S.Diag(getAttrLoc(AI), diag::err_attribute_argument_type)
- << &AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange();
- return false;
- }
-
- if (!I->isIntN(32)) {
- S.Diag(Expr->getExprLoc(), diag::err_ice_too_large)
- << toString(*I, 10, false) << 32 << /* Unsigned */ 1;
- return false;
- }
-
- if (StrictlyUnsigned && I->isSigned() && I->isNegative()) {
- S.Diag(getAttrLoc(AI), diag::err_attribute_requires_positive_integer)
- << &AI << /*non-negative*/ 1;
- return false;
- }
-
- Val = (uint32_t)I->getZExtValue();
- return true;
-}
+SourceLocation Sema::getAttrLoc(const ParsedAttr &AL) { return AL.getLoc(); }
/// Wrapper around checkUInt32Argument, with an extra check to be sure
/// that the result will fit into a regular (signed) int. All args have the same
@@ -254,7 +96,7 @@ template <typename AttrInfo>
static bool checkPositiveIntArgument(Sema &S, const AttrInfo &AI, const Expr *Expr,
int &Val, unsigned Idx = UINT_MAX) {
uint32_t UVal;
- if (!checkUInt32Argument(S, AI, Expr, UVal, Idx))
+ if (!S.checkUInt32Argument(AI, Expr, UVal, Idx))
return false;
if (UVal > (uint32_t)std::numeric_limits<int>::max()) {
@@ -269,80 +111,6 @@ static bool checkPositiveIntArgument(Sema &S, const AttrInfo &AI, const Expr *Ex
return true;
}
-/// Diagnose mutually exclusive attributes when present on a given
-/// declaration. Returns true if diagnosed.
-template <typename AttrTy>
-static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (const auto *A = D->getAttr<AttrTy>()) {
- S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
- << AL << A
- << (AL.isRegularKeywordAttribute() || A->isRegularKeywordAttribute());
- S.Diag(A->getLocation(), diag::note_conflicting_attribute);
- return true;
- }
- return false;
-}
-
-template <typename AttrTy>
-static bool checkAttrMutualExclusion(Sema &S, Decl *D, const Attr &AL) {
- if (const auto *A = D->getAttr<AttrTy>()) {
- S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible)
- << &AL << A
- << (AL.isRegularKeywordAttribute() || A->isRegularKeywordAttribute());
- S.Diag(A->getLocation(), diag::note_conflicting_attribute);
- return true;
- }
- return false;
-}
-
-/// Check if IdxExpr is a valid parameter index for a function or
-/// instance method D. May output an error.
-///
-/// \returns true if IdxExpr is a valid index.
-template <typename AttrInfo>
-static bool checkFunctionOrMethodParameterIndex(
- Sema &S, const Decl *D, const AttrInfo &AI, unsigned AttrArgNum,
- const Expr *IdxExpr, ParamIdx &Idx, bool CanIndexImplicitThis = false) {
- assert(isFunctionOrMethodOrBlock(D));
-
- // In C++ the implicit 'this' function parameter also counts.
- // Parameters are counted from one.
- bool HP = hasFunctionProto(D);
- bool HasImplicitThisParam = isInstanceMethod(D);
- bool IV = HP && isFunctionOrMethodVariadic(D);
- unsigned NumParams =
- (HP ? getFunctionOrMethodNumParams(D) : 0) + HasImplicitThisParam;
-
- std::optional<llvm::APSInt> IdxInt;
- if (IdxExpr->isTypeDependent() ||
- !(IdxInt = IdxExpr->getIntegerConstantExpr(S.Context))) {
- S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type)
- << &AI << AttrArgNum << AANT_ArgumentIntegerConstant
- << IdxExpr->getSourceRange();
- return false;
- }
-
- unsigned IdxSource = IdxInt->getLimitedValue(UINT_MAX);
- if (IdxSource < 1 || (!IV && IdxSource > NumParams)) {
- S.Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds)
- << &AI << AttrArgNum << IdxExpr->getSourceRange();
- return false;
- }
- if (HasImplicitThisParam && !CanIndexImplicitThis) {
- if (IdxSource == 1) {
- S.Diag(getAttrLoc(AI), diag::err_attribute_invalid_implicit_this_argument)
- << &AI << IdxExpr->getSourceRange();
- return false;
- }
- }
-
- Idx = ParamIdx(IdxSource, D);
- return true;
-}
-
-/// Check if the argument \p E is a ASCII string literal. If not emit an error
-/// and return false, otherwise set \p Str to the value of the string literal
-/// and return true.
bool Sema::checkStringLiteralArgumentAttr(const AttributeCommonInfo &CI,
const Expr *E, StringRef &Str,
SourceLocation *ArgLocation) {
@@ -360,10 +128,6 @@ bool Sema::checkStringLiteralArgumentAttr(const AttributeCommonInfo &CI,
return true;
}
-/// Check if the argument \p ArgNum of \p Attr is a ASCII string literal.
-/// If not emit an error and return false. If the argument is an identifier it
-/// will emit an error with a fixit hint and treat it as if it was a string
-/// literal.
bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum,
StringRef &Str,
SourceLocation *ArgLocation) {
@@ -395,45 +159,6 @@ bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum,
return checkStringLiteralArgumentAttr(AL, ArgExpr, Str, ArgLocation);
}
-/// Applies the given attribute to the Decl without performing any
-/// additional semantic checking.
-template <typename AttrType>
-static void handleSimpleAttribute(Sema &S, Decl *D,
- const AttributeCommonInfo &CI) {
- D->addAttr(::new (S.Context) AttrType(S.Context, CI));
-}
-
-template <typename... DiagnosticArgs>
-static const Sema::SemaDiagnosticBuilder&
-appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr) {
- return Bldr;
-}
-
-template <typename T, typename... DiagnosticArgs>
-static const Sema::SemaDiagnosticBuilder&
-appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr, T &&ExtraArg,
- DiagnosticArgs &&... ExtraArgs) {
- return appendDiagnostics(Bldr << std::forward<T>(ExtraArg),
- std::forward<DiagnosticArgs>(ExtraArgs)...);
-}
-
-/// Add an attribute @c AttrType to declaration @c D, provided that
-/// @c PassesCheck is true.
-/// Otherwise, emit diagnostic @c DiagID, passing in all parameters
-/// specified in @c ExtraArgs.
-template <typename AttrType, typename... DiagnosticArgs>
-static void handleSimpleAttributeOrDiagnose(Sema &S, Decl *D,
- const AttributeCommonInfo &CI,
- bool PassesCheck, unsigned DiagID,
- DiagnosticArgs &&... ExtraArgs) {
- if (!PassesCheck) {
- Sema::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID);
- appendDiagnostics(DB, std::forward<DiagnosticArgs>(ExtraArgs)...);
- return;
- }
- handleSimpleAttribute<AttrType>(S, D, CI);
-}
-
/// Check if the passed-in expression is of type int or bool.
static bool isIntOrBool(Expr *Exp) {
QualType QT = Exp->getType();
@@ -635,7 +360,7 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D,
if (const auto *StrLit = dyn_cast<StringLiteral>(ArgExp)) {
if (StrLit->getLength() == 0 ||
- (StrLit->isOrdinary() && StrLit->getString() == StringRef("*"))) {
+ (StrLit->isOrdinary() && StrLit->getString() == "*")) {
// Pass empty strings to the analyzer without warnings.
// Treat "*" as the universal lock.
Args.push_back(ArgExp);
@@ -820,8 +545,8 @@ static bool checkParamIsIntegerType(Sema &S, const Decl *D, const AttrInfo &AI,
assert(AI.isArgExpr(AttrArgNo) && "Expected expression argument");
Expr *AttrArg = AI.getArgAsExpr(AttrArgNo);
ParamIdx Idx;
- if (!checkFunctionOrMethodParameterIndex(S, D, AI, AttrArgNo + 1, AttrArg,
- Idx))
+ if (!S.checkFunctionOrMethodParameterIndex(D, AI, AttrArgNo + 1, AttrArg,
+ Idx))
return false;
QualType ParamTy = getFunctionOrMethodParamType(D, Idx.getASTIndex());
@@ -838,7 +563,7 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 2))
return;
- assert(isFunctionOrMethod(D) && hasFunctionProto(D));
+ assert(isFuncOrMethodForAttrSubject(D) && hasFunctionProto(D));
QualType RetTy = getFunctionOrMethodResultType(D);
if (!RetTy->isPointerType()) {
@@ -980,6 +705,21 @@ static void handleErrorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(EA);
}
+static void handleExcludeFromExplicitInstantiationAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ const auto *PD = isa<CXXRecordDecl>(D)
+ ? cast<DeclContext>(D)
+ : D->getDeclContext()->getRedeclContext();
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(PD); RD && RD->isLocalClass()) {
+ S.Diag(AL.getLoc(),
+ diag::warn_attribute_exclude_from_explicit_instantiation_local_class)
+ << AL << /*IsMember=*/!isa<CXXRecordDecl>(D);
+ return;
+ }
+ D->addAttr(::new (S.Context)
+ ExcludeFromExplicitInstantiationAttr(S.Context, AL));
+}
+
namespace {
/// Determines if a given Expr references any of the given function's
/// ParmVarDecls, or the function's implicit `this` parameter (if applicable).
@@ -1078,7 +818,7 @@ static void handleDiagnoseAsBuiltinAttr(Sema &S, Decl *D,
const Expr *IndexExpr = AL.getArgAsExpr(I);
uint32_t Index;
- if (!checkUInt32Argument(S, AL, IndexExpr, Index, I + 1, false))
+ if (!S.checkUInt32Argument(AL, IndexExpr, Index, I + 1, false))
return;
if (Index > DeclFD->getNumParams()) {
@@ -1188,7 +928,7 @@ static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expr *E = AL.getArgAsExpr(0);
uint32_t Type;
- if (!checkUInt32Argument(S, AL, E, Type, /*Idx=*/1))
+ if (!S.checkUInt32Argument(AL, E, Type, /*Idx=*/1))
return;
// pass_object_size's argument is passed in as the second argument of
@@ -1475,82 +1215,6 @@ static void handlePreferredName(Sema &S, Decl *D, const ParsedAttr &AL) {
<< TT->getDecl();
}
-static bool checkIBOutletCommon(Sema &S, Decl *D, const ParsedAttr &AL) {
- // The IBOutlet/IBOutletCollection attributes only apply to instance
- // variables or properties of Objective-C classes. The outlet must also
- // have an object reference type.
- if (const auto *VD = dyn_cast<ObjCIvarDecl>(D)) {
- if (!VD->getType()->getAs<ObjCObjectPointerType>()) {
- S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type)
- << AL << VD->getType() << 0;
- return false;
- }
- }
- else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) {
- if (!PD->getType()->getAs<ObjCObjectPointerType>()) {
- S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type)
- << AL << PD->getType() << 1;
- return false;
- }
- }
- else {
- S.Diag(AL.getLoc(), diag::warn_attribute_iboutlet) << AL;
- return false;
- }
-
- return true;
-}
-
-static void handleIBOutlet(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!checkIBOutletCommon(S, D, AL))
- return;
-
- D->addAttr(::new (S.Context) IBOutletAttr(S.Context, AL));
-}
-
-static void handleIBOutletCollection(Sema &S, Decl *D, const ParsedAttr &AL) {
-
- // The iboutletcollection attribute can have zero or one arguments.
- if (AL.getNumArgs() > 1) {
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
- return;
- }
-
- if (!checkIBOutletCommon(S, D, AL))
- return;
-
- ParsedType PT;
-
- if (AL.hasParsedType())
- PT = AL.getTypeArg();
- else {
- PT = S.getTypeName(S.Context.Idents.get("NSObject"), AL.getLoc(),
- S.getScopeForContext(D->getDeclContext()->getParent()));
- if (!PT) {
- S.Diag(AL.getLoc(), diag::err_iboutletcollection_type) << "NSObject";
- return;
- }
- }
-
- TypeSourceInfo *QTLoc = nullptr;
- QualType QT = S.GetTypeFromParser(PT, &QTLoc);
- if (!QTLoc)
- QTLoc = S.Context.getTrivialTypeSourceInfo(QT, AL.getLoc());
-
- // Diagnose use of non-object type in iboutletcollection attribute.
- // FIXME. Gnu attribute extension ignores use of builtin types in
- // attributes. So, __attribute__((iboutletcollection(char))) will be
- // treated as __attribute__((iboutletcollection())).
- if (!QT->isObjCIdType() && !QT->isObjCObjectType()) {
- S.Diag(AL.getLoc(),
- QT->isBuiltinType() ? diag::err_iboutletcollection_builtintype
- : diag::err_iboutletcollection_type) << QT;
- return;
- }
-
- D->addAttr(::new (S.Context) IBOutletCollectionAttr(S.Context, AL, QTLoc));
-}
-
bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) {
if (RefOkay) {
if (T->isReferenceType())
@@ -1596,7 +1260,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
for (unsigned I = 0; I < AL.getNumArgs(); ++I) {
Expr *Ex = AL.getArgAsExpr(I);
ParamIdx Idx;
- if (!checkFunctionOrMethodParameterIndex(S, D, AL, I + 1, Ex, Idx))
+ if (!S.checkFunctionOrMethodParameterIndex(D, AL, I + 1, Ex, Idx))
return;
// Is the function argument a pointer type?
@@ -1754,7 +1418,7 @@ void Sema::AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI,
ParamIdx Idx;
const auto *FuncDecl = cast<FunctionDecl>(D);
- if (!checkFunctionOrMethodParameterIndex(*this, FuncDecl, TmpAttr,
+ if (!checkFunctionOrMethodParameterIndex(FuncDecl, TmpAttr,
/*AttrArgNum=*/1, ParamExpr, Idx))
return;
@@ -1770,42 +1434,6 @@ void Sema::AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI,
D->addAttr(::new (Context) AllocAlignAttr(Context, CI, Idx));
}
-/// Check if \p AssumptionStr is a known assumption and warn if not.
-static void checkAssumptionAttr(Sema &S, SourceLocation Loc,
- StringRef AssumptionStr) {
- if (llvm::KnownAssumptionStrings.count(AssumptionStr))
- return;
-
- unsigned BestEditDistance = 3;
- StringRef Suggestion;
- for (const auto &KnownAssumptionIt : llvm::KnownAssumptionStrings) {
- unsigned EditDistance =
- AssumptionStr.edit_distance(KnownAssumptionIt.getKey());
- if (EditDistance < BestEditDistance) {
- Suggestion = KnownAssumptionIt.getKey();
- BestEditDistance = EditDistance;
- }
- }
-
- if (!Suggestion.empty())
- S.Diag(Loc, diag::warn_assume_attribute_string_unknown_suggested)
- << AssumptionStr << Suggestion;
- else
- S.Diag(Loc, diag::warn_assume_attribute_string_unknown) << AssumptionStr;
-}
-
-static void handleAssumumptionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Handle the case where the attribute has a text message.
- StringRef Str;
- SourceLocation AttrStrLoc;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &AttrStrLoc))
- return;
-
- checkAssumptionAttr(S, AttrStrLoc, Str);
-
- D->addAttr(::new (S.Context) AssumptionAttr(S.Context, AL, Str));
-}
-
/// Normalize the attribute, __foo__ becomes foo.
/// Returns true if normalization was applied.
static bool normalizeName(StringRef &AttrName) {
@@ -1864,7 +1492,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
for (unsigned i = 1; i < AL.getNumArgs(); ++i) {
Expr *Ex = AL.getArgAsExpr(i);
ParamIdx Idx;
- if (!checkFunctionOrMethodParameterIndex(S, D, AL, i, Ex, Idx))
+ if (!S.checkFunctionOrMethodParameterIndex(D, AL, i, Ex, Idx))
return;
// Is the function argument a pointer type?
@@ -1979,6 +1607,38 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(::new (S.Context) WeakRefAttr(S.Context, AL));
}
+// Mark alias/ifunc target as used. Due to name mangling, we look up the
+// demangled name ignoring parameters (not supported by microsoftDemangle
+// https://github.com/llvm/llvm-project/issues/88825). This should handle the
+// majority of use cases while leaving namespace scope names unmarked.
+static void markUsedForAliasOrIfunc(Sema &S, Decl *D, const ParsedAttr &AL,
+ StringRef Str) {
+ std::unique_ptr<char, llvm::FreeDeleter> Demangled;
+ if (S.getASTContext().getCXXABIKind() != TargetCXXABI::Microsoft)
+ Demangled.reset(llvm::itaniumDemangle(Str, /*ParseParams=*/false));
+ std::unique_ptr<MangleContext> MC(S.Context.createMangleContext());
+ SmallString<256> Name;
+
+ const DeclarationNameInfo Target(
+ &S.Context.Idents.get(Demangled ? Demangled.get() : Str), AL.getLoc());
+ LookupResult LR(S, Target, Sema::LookupOrdinaryName);
+ if (S.LookupName(LR, S.TUScope)) {
+ for (NamedDecl *ND : LR) {
+ if (!isa<FunctionDecl>(ND) && !isa<VarDecl>(ND))
+ continue;
+ if (MC->shouldMangleDeclName(ND)) {
+ llvm::raw_svector_ostream Out(Name);
+ Name.clear();
+ MC->mangleName(GlobalDecl(ND), Out);
+ } else {
+ Name = ND->getIdentifier()->getName();
+ }
+ if (Name == Str)
+ ND->markUsed(S.Context);
+ }
+ }
+}
+
static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
@@ -1991,6 +1651,7 @@ static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
+ markUsedForAliasOrIfunc(S, D, AL, Str);
D->addAttr(::new (S.Context) IFuncAttr(S.Context, AL, Str));
}
@@ -2025,17 +1686,7 @@ static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
- // Mark target used to prevent unneeded-internal-declaration warnings.
- if (!S.LangOpts.CPlusPlus) {
- // FIXME: demangle Str for C++, as the attribute refers to the mangled
- // linkage name, not the pre-mangled identifier.
- const DeclarationNameInfo target(&S.Context.Idents.get(Str), AL.getLoc());
- LookupResult LR(S, target, Sema::LookupOrdinaryName);
- if (S.LookupQualifiedName(LR, S.getCurLexicalContext()))
- for (NamedDecl *ND : LR)
- ND->markUsed(S.Context);
- }
-
+ markUsedForAliasOrIfunc(S, D, AL, Str);
D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str));
}
@@ -2053,12 +1704,6 @@ static void handleTLSModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- if (S.Context.getTargetInfo().getTriple().isOSAIX() &&
- Model == "local-dynamic") {
- S.Diag(LiteralLoc, diag::err_aix_attr_unsupported_tls_model) << Model;
- return;
- }
-
D->addAttr(::new (S.Context) TLSModelAttr(S.Context, AL, Model));
}
@@ -2155,21 +1800,6 @@ static void handleCommonAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(::new (S.Context) CommonAttr(S.Context, AL));
}
-static void handleCmseNSEntryAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (S.LangOpts.CPlusPlus && !D->getDeclContext()->isExternCContext()) {
- S.Diag(AL.getLoc(), diag::err_attribute_not_clinkage) << AL;
- return;
- }
-
- const auto *FD = cast<FunctionDecl>(D);
- if (!FD->isExternallyVisible()) {
- S.Diag(AL.getLoc(), diag::warn_attribute_cmse_entry_static);
- return;
- }
-
- D->addAttr(::new (S.Context) CmseNSEntryAttr(S.Context, AL));
-}
-
static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (AL.isDeclspecAttribute()) {
const auto &Triple = S.getASTContext().getTargetInfo().getTriple();
@@ -2255,7 +1885,7 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// The checking path for 'noreturn' and 'analyzer_noreturn' are different
// because 'analyzer_noreturn' does not impact the type.
- if (!isFunctionOrMethodOrBlock(D)) {
+ if (!isFunctionOrMethodOrBlockForAttrSubject(D)) {
ValueDecl *VD = dyn_cast<ValueDecl>(D);
if (!VD || (!VD->getType()->isBlockPointerType() &&
!VD->getType()->isFunctionPointerType())) {
@@ -2359,7 +1989,7 @@ static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
if (AL.getNumArgs() &&
- !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority))
+ !S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority))
return;
D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority));
@@ -2368,7 +1998,7 @@ static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
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))
+ !S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority))
return;
D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority));
@@ -2384,17 +2014,6 @@ static void handleAttrWithMessage(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(::new (S.Context) AttrTy(S.Context, AL, Str));
}
-static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- if (!cast<ObjCProtocolDecl>(D)->isThisDeclarationADefinition()) {
- S.Diag(AL.getLoc(), diag::err_objc_attr_protocol_requires_definition)
- << AL << AL.getRange();
- return;
- }
-
- D->addAttr(::new (S.Context) ObjCExplicitProtocolImplAttr(S.Context, AL));
-}
-
static bool checkAvailabilityAttr(Sema &S, SourceRange Range,
IdentifierInfo *Platform,
VersionTuple Introduced,
@@ -2457,7 +2076,7 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(
bool Implicit, VersionTuple Introduced, VersionTuple Deprecated,
VersionTuple Obsoleted, bool IsUnavailable, StringRef Message,
bool IsStrict, StringRef Replacement, AvailabilityMergeKind AMK,
- int Priority) {
+ int Priority, IdentifierInfo *Environment) {
VersionTuple MergedIntroduced = Introduced;
VersionTuple MergedDeprecated = Deprecated;
VersionTuple MergedObsoleted = Obsoleted;
@@ -2491,6 +2110,12 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(
continue;
}
+ IdentifierInfo *OldEnvironment = OldAA->getEnvironment();
+ if (OldEnvironment != Environment) {
+ ++i;
+ continue;
+ }
+
// If there is an existing availability attribute for this platform that
// has a lower priority use the existing one and discard the new
// attribute.
@@ -2609,7 +2234,7 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(
!OverrideOrImpl) {
auto *Avail = ::new (Context) AvailabilityAttr(
Context, CI, Platform, Introduced, Deprecated, Obsoleted, IsUnavailable,
- Message, IsStrict, Replacement, Priority);
+ Message, IsStrict, Replacement, Priority, Environment);
Avail->setImplicit(Implicit);
return Avail;
}
@@ -2668,13 +2293,34 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
+ if (S.getLangOpts().HLSL && IsStrict)
+ S.Diag(AL.getStrictLoc(), diag::err_availability_unexpected_parameter)
+ << "strict" << /* HLSL */ 0;
+
int PriorityModifier = AL.isPragmaClangAttribute()
? Sema::AP_PragmaClangAttribute
: Sema::AP_Explicit;
+
+ const IdentifierLoc *EnvironmentLoc = AL.getEnvironment();
+ IdentifierInfo *IIEnvironment = nullptr;
+ if (EnvironmentLoc) {
+ if (S.getLangOpts().HLSL) {
+ IIEnvironment = EnvironmentLoc->Ident;
+ if (AvailabilityAttr::getEnvironmentType(
+ EnvironmentLoc->Ident->getName()) ==
+ llvm::Triple::EnvironmentType::UnknownEnvironment)
+ S.Diag(EnvironmentLoc->Loc, diag::warn_availability_unknown_environment)
+ << EnvironmentLoc->Ident;
+ } else {
+ S.Diag(EnvironmentLoc->Loc, diag::err_availability_unexpected_parameter)
+ << "environment" << /* C/C++ */ 1;
+ }
+ }
+
AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
ND, AL, II, false /*Implicit*/, Introduced.Version, Deprecated.Version,
Obsoleted.Version, IsUnavailable, Str, IsStrict, Replacement,
- Sema::AMK_None, PriorityModifier);
+ Sema::AMK_None, PriorityModifier, IIEnvironment);
if (NewAttr)
D->addAttr(NewAttr);
@@ -2730,8 +2376,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated,
NewObsoleted, IsUnavailable, Str, IsStrict, Replacement,
- Sema::AMK_None,
- PriorityModifier + Sema::AP_InferredFromOtherPlatform);
+ Sema::AMK_None, PriorityModifier + Sema::AP_InferredFromOtherPlatform,
+ IIEnvironment);
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -2772,8 +2418,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated,
NewObsoleted, IsUnavailable, Str, IsStrict, Replacement,
- Sema::AMK_None,
- PriorityModifier + Sema::AP_InferredFromOtherPlatform);
+ Sema::AMK_None, PriorityModifier + Sema::AP_InferredFromOtherPlatform,
+ IIEnvironment);
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -2806,7 +2452,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
MinMacCatalystVersion(Deprecated.Version),
MinMacCatalystVersion(Obsoleted.Version), IsUnavailable, Str,
IsStrict, Replacement, Sema::AMK_None,
- PriorityModifier + Sema::AP_InferredFromOtherPlatform);
+ PriorityModifier + Sema::AP_InferredFromOtherPlatform, IIEnvironment);
if (NewAttr)
D->addAttr(NewAttr);
} else if (II->getName() == "macos" && GetSDKInfo() &&
@@ -2849,7 +2495,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
VersionOrEmptyVersion(NewObsoleted), /*IsUnavailable=*/false, Str,
IsStrict, Replacement, Sema::AMK_None,
PriorityModifier + Sema::AP_InferredFromOtherPlatform +
- Sema::AP_InferredFromOtherPlatform);
+ Sema::AP_InferredFromOtherPlatform,
+ IIEnvironment);
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -2953,113 +2600,6 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL,
D->addAttr(newAttr);
}
-static void handleObjCDirectAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // objc_direct cannot be set on methods declared in the context of a protocol
- if (isa<ObjCProtocolDecl>(D->getDeclContext())) {
- S.Diag(AL.getLoc(), diag::err_objc_direct_on_protocol) << false;
- return;
- }
-
- if (S.getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
- handleSimpleAttribute<ObjCDirectAttr>(S, D, AL);
- } else {
- S.Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL;
- }
-}
-
-static void handleObjCDirectMembersAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- if (S.getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
- handleSimpleAttribute<ObjCDirectMembersAttr>(S, D, AL);
- } else {
- S.Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL;
- }
-}
-
-static void handleObjCMethodFamilyAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- const auto *M = cast<ObjCMethodDecl>(D);
- if (!AL.isArgIdent(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
- << AL << 1 << AANT_ArgumentIdentifier;
- return;
- }
-
- IdentifierLoc *IL = AL.getArgAsIdent(0);
- ObjCMethodFamilyAttr::FamilyKind F;
- if (!ObjCMethodFamilyAttr::ConvertStrToFamilyKind(IL->Ident->getName(), F)) {
- S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL << IL->Ident;
- return;
- }
-
- if (F == ObjCMethodFamilyAttr::OMF_init &&
- !M->getReturnType()->isObjCObjectPointerType()) {
- S.Diag(M->getLocation(), diag::err_init_method_bad_return_type)
- << M->getReturnType();
- // Ignore the attribute.
- return;
- }
-
- D->addAttr(new (S.Context) ObjCMethodFamilyAttr(S.Context, AL, F));
-}
-
-static void handleObjCNSObject(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
- QualType T = TD->getUnderlyingType();
- if (!T->isCARCBridgableType()) {
- S.Diag(TD->getLocation(), diag::err_nsobject_attribute);
- return;
- }
- }
- else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) {
- QualType T = PD->getType();
- if (!T->isCARCBridgableType()) {
- S.Diag(PD->getLocation(), diag::err_nsobject_attribute);
- return;
- }
- }
- else {
- // It is okay to include this attribute on properties, e.g.:
- //
- // @property (retain, nonatomic) struct Bork *Q __attribute__((NSObject));
- //
- // In this case it follows tradition and suppresses an error in the above
- // case.
- S.Diag(D->getLocation(), diag::warn_nsobject_attribute);
- }
- D->addAttr(::new (S.Context) ObjCNSObjectAttr(S.Context, AL));
-}
-
-static void handleObjCIndependentClass(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
- QualType T = TD->getUnderlyingType();
- if (!T->isObjCObjectPointerType()) {
- S.Diag(TD->getLocation(), diag::warn_ptr_independentclass_attribute);
- return;
- }
- } else {
- S.Diag(D->getLocation(), diag::warn_independentclass_attribute);
- return;
- }
- D->addAttr(::new (S.Context) ObjCIndependentClassAttr(S.Context, AL));
-}
-
-static void handleBlocksAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!AL.isArgIdent(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
- << AL << 1 << AANT_ArgumentIdentifier;
- return;
- }
-
- IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
- BlocksAttr::BlockType type;
- if (!BlocksAttr::ConvertStrToBlockType(II->getName(), type)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II;
- return;
- }
-
- D->addAttr(::new (S.Context) BlocksAttr(S.Context, AL, type));
-}
-
static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
unsigned sentinel = (unsigned)SentinelAttr::DefaultSentinel;
if (AL.getNumArgs() > 0) {
@@ -3229,8 +2769,8 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) {
uint32_t WGSize[3];
for (unsigned i = 0; i < 3; ++i) {
const Expr *E = AL.getArgAsExpr(i);
- if (!checkUInt32Argument(S, AL, E, WGSize[i], i,
- /*StrictlyUnsigned=*/true))
+ if (!S.checkUInt32Argument(AL, E, WGSize[i], i,
+ /*StrictlyUnsigned=*/true))
return;
if (WGSize[i] == 0) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero)
@@ -3249,27 +2789,6 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) {
WorkGroupAttr(S.Context, AL, WGSize[0], WGSize[1], WGSize[2]));
}
-// Handles intel_reqd_sub_group_size.
-static void handleSubGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) {
- uint32_t SGSize;
- const Expr *E = AL.getArgAsExpr(0);
- if (!checkUInt32Argument(S, AL, E, SGSize))
- return;
- if (SGSize == 0) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero)
- << AL << E->getSourceRange();
- return;
- }
-
- OpenCLIntelReqdSubGroupSizeAttr *Existing =
- D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>();
- if (Existing && Existing->getSubGroupSize() != SGSize)
- S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
-
- D->addAttr(::new (S.Context)
- OpenCLIntelReqdSubGroupSizeAttr(S.Context, AL, SGSize));
-}
-
static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!AL.hasParsedType()) {
S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
@@ -3317,15 +2836,6 @@ SectionAttr *Sema::mergeSectionAttr(Decl *D, const AttributeCommonInfo &CI,
return ::new (Context) SectionAttr(Context, CI, Name);
}
-/// Used to implement to perform semantic checking on
-/// attribute((section("foo"))) specifiers.
-///
-/// In this case, "foo" is passed in to be checked. If the section
-/// specifier is invalid, return an Error that indicates the problem.
-///
-/// This is a simple quality of implementation feature to catch errors
-/// and give good diagnostics in cases when the assembler or code generator
-/// would otherwise reject the section specifier.
llvm::Error Sema::isValidSectionSpecifier(StringRef SecName) {
if (!Context.getTargetInfo().getTriple().isOSDarwin())
return llvm::Error::success();
@@ -3438,8 +2948,6 @@ static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(CSA);
}
-// Check for things we'd like to warn about. Multiversioning issues are
-// handled later in the process, once we know how many exist.
bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
enum FirstParam { Unsupported, Duplicate, Unknown };
enum SecondParam { None, CPU, Tune };
@@ -3483,7 +2991,7 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
<< Unsupported << None << CurFeature << Target;
}
- TargetInfo::BranchProtectionInfo BPI;
+ TargetInfo::BranchProtectionInfo BPI{};
StringRef DiagMsg;
if (ParsedAttrs.BranchProtection.empty())
return false;
@@ -3501,14 +3009,11 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
return false;
}
-// Check Target Version attrs
-bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, StringRef &AttrStr,
- bool &isDefault) {
+bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D,
+ StringRef AttrStr) {
enum FirstParam { Unsupported };
enum SecondParam { None };
enum ThirdParam { Target, TargetClones, TargetVersion };
- if (AttrStr.trim() == "default")
- isDefault = true;
llvm::SmallVector<StringRef, 8> Features;
AttrStr.split(Features, "+");
for (auto &CurFeature : Features) {
@@ -3525,16 +3030,12 @@ bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, StringRef &AttrStr,
static void handleTargetVersionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
SourceLocation LiteralLoc;
- bool isDefault = false;
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) ||
- S.checkTargetVersionAttr(LiteralLoc, Str, isDefault))
+ S.checkTargetVersionAttr(LiteralLoc, D, Str))
return;
- // Do not create default only target_version attribute
- if (!isDefault) {
- TargetVersionAttr *NewAttr =
- ::new (S.Context) TargetVersionAttr(S.Context, AL, Str);
- D->addAttr(NewAttr);
- }
+ TargetVersionAttr *NewAttr =
+ ::new (S.Context) TargetVersionAttr(S.Context, AL, Str);
+ D->addAttr(NewAttr);
}
static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -3550,7 +3051,7 @@ static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
bool Sema::checkTargetClonesAttrString(
SourceLocation LiteralLoc, StringRef Str, const StringLiteral *Literal,
- bool &HasDefault, bool &HasCommas, bool &HasNotDefault,
+ Decl *D, bool &HasDefault, bool &HasCommas, bool &HasNotDefault,
SmallVectorImpl<SmallString<64>> &StringsBuffer) {
enum FirstParam { Unsupported, Duplicate, Unknown };
enum SecondParam { None, CPU, Tune };
@@ -3604,7 +3105,7 @@ bool Sema::checkTargetClonesAttrString(
llvm::sort(CurFeatures);
SmallString<64> Res;
for (auto &CurFeat : CurFeatures) {
- if (!Res.equals(""))
+ if (!Res.empty())
Res.append("+");
Res.append(CurFeat);
}
@@ -3670,7 +3171,7 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!S.checkStringLiteralArgumentAttr(AL, I, CurStr, &LiteralLoc) ||
S.checkTargetClonesAttrString(
LiteralLoc, CurStr,
- cast<StringLiteral>(AL.getArgAsExpr(I)->IgnoreParenCasts()),
+ cast<StringLiteral>(AL.getArgAsExpr(I)->IgnoreParenCasts()), D,
HasDefault, HasCommas, HasNotDefault, StringsBuffer))
return;
}
@@ -3715,7 +3216,7 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
static void handleMinVectorWidthAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expr *E = AL.getArgAsExpr(0);
uint32_t VecWidth;
- if (!checkUInt32Argument(S, AL, E, VecWidth)) {
+ if (!S.checkUInt32Argument(AL, E, VecWidth)) {
AL.setInvalid();
return;
}
@@ -3780,6 +3281,30 @@ static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
<< NI.getName() << ParamTy << Ty;
return;
}
+ VarDecl *VD = cast<VarDecl>(D);
+ // Create a reference to the variable declaration. This is a fake/dummy
+ // reference.
+ DeclRefExpr *VariableReference = DeclRefExpr::Create(
+ S.Context, NestedNameSpecifierLoc{}, FD->getLocation(), VD, false,
+ DeclarationNameInfo{VD->getDeclName(), VD->getLocation()}, VD->getType(),
+ VK_LValue);
+
+ // Create a unary operator expression that represents taking the address of
+ // the variable. This is a fake/dummy expression.
+ Expr *AddressOfVariable = UnaryOperator::Create(
+ S.Context, VariableReference, UnaryOperatorKind::UO_AddrOf,
+ S.Context.getPointerType(VD->getType()), VK_PRValue, OK_Ordinary, Loc,
+ +false, FPOptionsOverride{});
+
+ // Create a function call expression. This is a fake/dummy call expression.
+ CallExpr *FunctionCallExpression =
+ CallExpr::Create(S.Context, E, ArrayRef{AddressOfVariable},
+ S.Context.VoidTy, VK_PRValue, Loc, FPOptionsOverride{});
+
+ if (S.CheckFunctionCall(FD, FunctionCallExpression,
+ FD->getType()->getAs<FunctionProtoType>())) {
+ return;
+ }
D->addAttr(::new (S.Context) CleanupAttr(S.Context, AL, FD));
}
@@ -3809,15 +3334,14 @@ static void handleEnumExtensibilityAttr(Sema &S, Decl *D,
static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
const Expr *IdxExpr = AL.getArgAsExpr(0);
ParamIdx Idx;
- if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, IdxExpr, Idx))
+ if (!S.checkFunctionOrMethodParameterIndex(D, AL, 1, IdxExpr, Idx))
return;
// Make sure the format string is really a string.
QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex());
- bool NotNSStringTy = !isNSStringType(Ty, S.Context);
- if (NotNSStringTy &&
- !isCFStringType(Ty, S.Context) &&
+ bool NotNSStringTy = !S.ObjC().isNSStringType(Ty);
+ if (NotNSStringTy && !S.ObjC().isCFStringType(Ty) &&
(!Ty->isPointerType() ||
!Ty->castAs<PointerType>()->getPointeeType()->isCharType())) {
S.Diag(AL.getLoc(), diag::err_format_attribute_not)
@@ -3832,8 +3356,8 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (auto *Interface = OMD->getClassInterface())
Ty = S.Context.getObjCObjectPointerType(
QualType(Interface->getTypeForDecl(), 0));
- if (!isNSStringType(Ty, S.Context, /*AllowNSAttributedString=*/true) &&
- !isCFStringType(Ty, S.Context) &&
+ if (!S.ObjC().isNSStringType(Ty, /*AllowNSAttributedString=*/true) &&
+ !S.ObjC().isCFStringType(Ty) &&
(!Ty->isPointerType() ||
!Ty->castAs<PointerType>()->getPointeeType()->isCharType())) {
S.Diag(AL.getLoc(), diag::err_format_attribute_result_not)
@@ -3904,7 +3428,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expr *E = AL.getArgAsExpr(0);
uint32_t prioritynum;
- if (!checkUInt32Argument(S, AL, E, prioritynum)) {
+ if (!S.checkUInt32Argument(AL, E, prioritynum)) {
AL.setInvalid();
return;
}
@@ -4003,7 +3527,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// checks for the 2nd argument
Expr *IdxExpr = AL.getArgAsExpr(1);
uint32_t Idx;
- if (!checkUInt32Argument(S, AL, IdxExpr, Idx, 2))
+ if (!S.checkUInt32Argument(AL, IdxExpr, Idx, 2))
return;
if (Idx < 1 || Idx > NumArgs) {
@@ -4028,8 +3552,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// make sure the format string is really a string
QualType Ty = getFunctionOrMethodParamType(D, ArgIdx);
- if (!isNSStringType(Ty, S.Context, true) &&
- !isCFStringType(Ty, S.Context) &&
+ if (!S.ObjC().isNSStringType(Ty, true) && !S.ObjC().isCFStringType(Ty) &&
(!Ty->isPointerType() ||
!Ty->castAs<PointerType>()->getPointeeType()->isCharType())) {
S.Diag(AL.getLoc(), diag::err_format_attribute_not)
@@ -4040,7 +3563,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// check the 3rd argument
Expr *FirstArgExpr = AL.getArgAsExpr(2);
uint32_t FirstArg;
- if (!checkUInt32Argument(S, AL, FirstArgExpr, FirstArg, 3))
+ if (!S.checkUInt32Argument(AL, FirstArgExpr, FirstArg, 3))
return;
// FirstArg == 0 is is always valid.
@@ -4128,8 +3651,8 @@ static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expr *IdxExpr = AL.getArgAsExpr(I);
// If the expression is not parseable as an int32_t we have a problem.
- if (!checkUInt32Argument(S, AL, IdxExpr, (uint32_t &)ArgIdx, I + 1,
- false)) {
+ if (!S.checkUInt32Argument(AL, IdxExpr, (uint32_t &)ArgIdx, I + 1,
+ false)) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
<< AL << (I + 1) << IdxExpr->getSourceRange();
return;
@@ -4871,7 +4394,9 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI,
NewElemTy = Context.getRealTypeForBitwidth(DestWidth, ExplicitType);
if (NewElemTy.isNull()) {
- Diag(AttrLoc, diag::err_machine_mode) << 1 /*Unsupported*/ << Name;
+ // Only emit diagnostic on host for 128-bit mode attribute
+ if (!(DestWidth == 128 && getLangOpts().CUDAIsDevice))
+ Diag(AttrLoc, diag::err_machine_mode) << 1 /*Unsupported*/ << Name;
return;
}
@@ -4987,22 +4512,6 @@ MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, const AttributeCommonInfo &CI) {
return ::new (Context) MinSizeAttr(Context, CI);
}
-SwiftNameAttr *Sema::mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA,
- StringRef Name) {
- if (const auto *PrevSNA = D->getAttr<SwiftNameAttr>()) {
- if (PrevSNA->getName() != Name && !PrevSNA->isImplicit()) {
- Diag(PrevSNA->getLocation(), diag::err_attributes_are_not_compatible)
- << PrevSNA << &SNA
- << (PrevSNA->isRegularKeywordAttribute() ||
- SNA.isRegularKeywordAttribute());
- Diag(SNA.getLoc(), diag::note_conflicting_attribute);
- }
-
- D->dropAttr<SwiftNameAttr>();
- }
- return ::new (Context) SwiftNameAttr(Context, SNA, Name);
-}
-
OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D,
const AttributeCommonInfo &CI) {
if (AlwaysInlineAttr *Inline = D->getAttr<AlwaysInlineAttr>()) {
@@ -5064,8 +4573,8 @@ static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
if (S.getLangOpts().CUDA && VD->hasLocalStorage() &&
- S.CUDADiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared)
- << S.CurrentCUDATarget())
+ S.CUDA().DiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared)
+ << llvm::to_underlying(S.CUDA().CurrentTarget()))
return;
D->addAttr(::new (S.Context) CUDASharedAttr(S.Context, AL));
}
@@ -5154,8 +4663,9 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Diagnostic is emitted elsewhere: here we store the (valid) AL
// in the Decl node for syntactic reasoning, e.g., pretty-printing.
CallingConv CC;
- if (S.CheckCallingConvAttr(AL, CC, /*FD*/ nullptr,
- S.IdentifyCUDATarget(dyn_cast<FunctionDecl>(D))))
+ if (S.CheckCallingConvAttr(
+ AL, CC, /*FD*/ nullptr,
+ S.CUDA().IdentifyTarget(dyn_cast<FunctionDecl>(D))))
return;
if (!isa<ObjCMethodDecl>(D)) {
@@ -5235,6 +4745,12 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
case ParsedAttr::AT_M68kRTD:
D->addAttr(::new (S.Context) M68kRTDAttr(S.Context, AL));
return;
+ case ParsedAttr::AT_PreserveNone:
+ D->addAttr(::new (S.Context) PreserveNoneAttr(S.Context, AL));
+ return;
+ case ParsedAttr::AT_RISCVVectorCC:
+ D->addAttr(::new (S.Context) RISCVVectorCCAttr(S.Context, AL));
+ return;
default:
llvm_unreachable("unexpected attribute kind");
}
@@ -5245,11 +4761,6 @@ static void handleSuppressAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Suppression attribute with GSL spelling requires at least 1 argument.
if (!AL.checkAtLeastNumArgs(S, 1))
return;
- } else if (!isa<VarDecl>(D)) {
- // Analyzer suppression applies only to variables and statements.
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type_str)
- << AL << 0 << "variables and statements";
- return;
}
std::vector<StringRef> DiagnosticIdentifiers;
@@ -5441,6 +4952,12 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
case ParsedAttr::AT_M68kRTD:
CC = CC_M68kRTD;
break;
+ case ParsedAttr::AT_PreserveNone:
+ CC = CC_PreserveNone;
+ break;
+ case ParsedAttr::AT_RISCVVectorCC:
+ CC = CC_RISCVVectorCall;
+ break;
default: llvm_unreachable("unexpected attribute kind");
}
@@ -5452,22 +4969,22 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
// on their host/device attributes.
if (LangOpts.CUDA) {
auto *Aux = Context.getAuxTargetInfo();
- assert(FD || CFT != CFT_InvalidTarget);
- auto CudaTarget = FD ? IdentifyCUDATarget(FD) : CFT;
+ assert(FD || CFT != CUDAFunctionTarget::InvalidTarget);
+ auto CudaTarget = FD ? CUDA().IdentifyTarget(FD) : CFT;
bool CheckHost = false, CheckDevice = false;
switch (CudaTarget) {
- case CFT_HostDevice:
+ case CUDAFunctionTarget::HostDevice:
CheckHost = true;
CheckDevice = true;
break;
- case CFT_Host:
+ case CUDAFunctionTarget::Host:
CheckHost = true;
break;
- case CFT_Device:
- case CFT_Global:
+ case CUDAFunctionTarget::Device:
+ case CUDAFunctionTarget::Global:
CheckDevice = true;
break;
- case CFT_InvalidTarget:
+ case CUDAFunctionTarget::InvalidTarget:
llvm_unreachable("unexpected cuda target");
}
auto *HostTI = LangOpts.CUDAIsDevice ? Aux : &TI;
@@ -5517,96 +5034,6 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
return false;
}
-/// Pointer-like types in the default address space.
-static bool isValidSwiftContextType(QualType Ty) {
- if (!Ty->hasPointerRepresentation())
- return Ty->isDependentType();
- return Ty->getPointeeType().getAddressSpace() == LangAS::Default;
-}
-
-/// Pointers and references in the default address space.
-static bool isValidSwiftIndirectResultType(QualType Ty) {
- if (const auto *PtrType = Ty->getAs<PointerType>()) {
- Ty = PtrType->getPointeeType();
- } else if (const auto *RefType = Ty->getAs<ReferenceType>()) {
- Ty = RefType->getPointeeType();
- } else {
- return Ty->isDependentType();
- }
- return Ty.getAddressSpace() == LangAS::Default;
-}
-
-/// Pointers and references to pointers in the default address space.
-static bool isValidSwiftErrorResultType(QualType Ty) {
- if (const auto *PtrType = Ty->getAs<PointerType>()) {
- Ty = PtrType->getPointeeType();
- } else if (const auto *RefType = Ty->getAs<ReferenceType>()) {
- Ty = RefType->getPointeeType();
- } else {
- return Ty->isDependentType();
- }
- if (!Ty.getQualifiers().empty())
- return false;
- return isValidSwiftContextType(Ty);
-}
-
-void Sema::AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI,
- ParameterABI abi) {
-
- QualType type = cast<ParmVarDecl>(D)->getType();
-
- if (auto existingAttr = D->getAttr<ParameterABIAttr>()) {
- if (existingAttr->getABI() != abi) {
- Diag(CI.getLoc(), diag::err_attributes_are_not_compatible)
- << getParameterABISpelling(abi) << existingAttr
- << (CI.isRegularKeywordAttribute() ||
- existingAttr->isRegularKeywordAttribute());
- Diag(existingAttr->getLocation(), diag::note_conflicting_attribute);
- return;
- }
- }
-
- switch (abi) {
- case ParameterABI::Ordinary:
- llvm_unreachable("explicit attribute for ordinary parameter ABI?");
-
- case ParameterABI::SwiftContext:
- if (!isValidSwiftContextType(type)) {
- Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type)
- << getParameterABISpelling(abi) << /*pointer to pointer */ 0 << type;
- }
- D->addAttr(::new (Context) SwiftContextAttr(Context, CI));
- return;
-
- case ParameterABI::SwiftAsyncContext:
- if (!isValidSwiftContextType(type)) {
- Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type)
- << getParameterABISpelling(abi) << /*pointer to pointer */ 0 << type;
- }
- D->addAttr(::new (Context) SwiftAsyncContextAttr(Context, CI));
- return;
-
- case ParameterABI::SwiftErrorResult:
- if (!isValidSwiftErrorResultType(type)) {
- Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type)
- << getParameterABISpelling(abi) << /*pointer to pointer */ 1 << type;
- }
- D->addAttr(::new (Context) SwiftErrorResultAttr(Context, CI));
- return;
-
- case ParameterABI::SwiftIndirectResult:
- if (!isValidSwiftIndirectResultType(type)) {
- Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type)
- << getParameterABISpelling(abi) << /*pointer*/ 0 << type;
- }
- D->addAttr(::new (Context) SwiftIndirectResultAttr(Context, CI));
- return;
- }
- llvm_unreachable("bad parameter ABI attribute");
-}
-
-/// Checks a regparm attribute, returning true if it is ill-formed and
-/// otherwise setting numParams to the appropriate value.
bool Sema::CheckRegparmAttr(const ParsedAttr &AL, unsigned &numParams) {
if (AL.isInvalid())
return true;
@@ -5618,7 +5045,7 @@ bool Sema::CheckRegparmAttr(const ParsedAttr &AL, unsigned &numParams) {
uint32_t NP;
Expr *NumParamsExpr = AL.getArgAsExpr(0);
- if (!checkUInt32Argument(*this, AL, NumParamsExpr, NP)) {
+ if (!checkUInt32Argument(AL, NumParamsExpr, NP)) {
AL.setInvalid();
return true;
}
@@ -5641,12 +5068,12 @@ bool Sema::CheckRegparmAttr(const ParsedAttr &AL, unsigned &numParams) {
return false;
}
-// Helper to get CudaArch.
-static CudaArch getCudaArch(const TargetInfo &TI) {
+// Helper to get OffloadArch.
+static OffloadArch getOffloadArch(const TargetInfo &TI) {
if (!TI.getTriple().isNVPTX())
- llvm_unreachable("getCudaArch is only valid for NVPTX triple");
+ llvm_unreachable("getOffloadArch is only valid for NVPTX triple");
auto &TO = TI.getTargetOpts();
- return StringToCudaArch(TO.CPU);
+ return StringToOffloadArch(TO.CPU);
}
// Checks whether an argument of launch_bounds attribute is
@@ -5706,10 +5133,10 @@ Sema::CreateLaunchBoundsAttr(const AttributeCommonInfo &CI, Expr *MaxThreads,
if (MaxBlocks) {
// '.maxclusterrank' ptx directive requires .target sm_90 or higher.
- auto SM = getCudaArch(Context.getTargetInfo());
- if (SM == CudaArch::UNKNOWN || SM < CudaArch::SM_90) {
+ auto SM = getOffloadArch(Context.getTargetInfo());
+ if (SM == OffloadArch::UNKNOWN || SM < OffloadArch::SM_90) {
Diag(MaxBlocks->getBeginLoc(), diag::warn_cuda_maxclusterrank_sm_90)
- << CudaArchToString(SM) << CI << MaxBlocks->getSourceRange();
+ << OffloadArchToString(SM) << CI << MaxBlocks->getSourceRange();
// Ignore it by setting MaxBlocks to null;
MaxBlocks = nullptr;
} else {
@@ -5748,13 +5175,13 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
}
ParamIdx ArgumentIdx;
- if (!checkFunctionOrMethodParameterIndex(S, D, AL, 2, AL.getArgAsExpr(1),
- ArgumentIdx))
+ if (!S.checkFunctionOrMethodParameterIndex(D, AL, 2, AL.getArgAsExpr(1),
+ ArgumentIdx))
return;
ParamIdx TypeTagIdx;
- if (!checkFunctionOrMethodParameterIndex(S, D, AL, 3, AL.getArgAsExpr(2),
- TypeTagIdx))
+ if (!S.checkFunctionOrMethodParameterIndex(D, AL, 3, AL.getArgAsExpr(2),
+ TypeTagIdx))
return;
bool IsPointer = AL.getAttrName()->getName() == "pointer_with_type_tag";
@@ -5801,9 +5228,9 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
ParamIdx ArgCount;
- if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, AL.getArgAsExpr(0),
- ArgCount,
- true /* CanIndexImplicitThis */))
+ if (!S.checkFunctionOrMethodParameterIndex(D, AL, 1, AL.getArgAsExpr(0),
+ ArgCount,
+ true /* CanIndexImplicitThis */))
return;
// ArgCount isn't a parameter index [0;n), it's a count [1;n]
@@ -5813,15 +5240,19 @@ static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D,
const ParsedAttr &AL) {
+ if (S.Context.getTargetInfo().getTriple().isOSAIX()) {
+ S.Diag(AL.getLoc(), diag::err_aix_attr_unsupported) << AL;
+ return;
+ }
uint32_t Count = 0, Offset = 0;
- if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Count, 0, true))
+ if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), Count, 0, true))
return;
if (AL.getNumArgs() == 2) {
Expr *Arg = AL.getArgAsExpr(1);
- if (!checkUInt32Argument(S, AL, Arg, Offset, 1, true))
+ if (!S.checkUInt32Argument(AL, Arg, Offset, 1, true))
return;
if (Count < Offset) {
- S.Diag(getAttrLoc(AL), diag::err_attribute_argument_out_of_range)
+ S.Diag(S.getAttrLoc(AL), diag::err_attribute_argument_out_of_range)
<< &AL << 0 << Count << Arg->getBeginLoc();
return;
}
@@ -5830,63 +5261,7 @@ static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D,
PatchableFunctionEntryAttr(S.Context, AL, Count, Offset));
}
-namespace {
-struct IntrinToName {
- uint32_t Id;
- int32_t FullName;
- int32_t ShortName;
-};
-} // unnamed namespace
-
-static bool ArmBuiltinAliasValid(unsigned BuiltinID, StringRef AliasName,
- ArrayRef<IntrinToName> Map,
- const char *IntrinNames) {
- AliasName.consume_front("__arm_");
- const IntrinToName *It =
- llvm::lower_bound(Map, BuiltinID, [](const IntrinToName &L, unsigned Id) {
- return L.Id < Id;
- });
- if (It == Map.end() || It->Id != BuiltinID)
- return false;
- StringRef FullName(&IntrinNames[It->FullName]);
- if (AliasName == FullName)
- return true;
- if (It->ShortName == -1)
- return false;
- StringRef ShortName(&IntrinNames[It->ShortName]);
- return AliasName == ShortName;
-}
-
-static bool ArmMveAliasValid(unsigned BuiltinID, StringRef AliasName) {
-#include "clang/Basic/arm_mve_builtin_aliases.inc"
- // The included file defines:
- // - ArrayRef<IntrinToName> Map
- // - const char IntrinNames[]
- return ArmBuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
-}
-
-static bool ArmCdeAliasValid(unsigned BuiltinID, StringRef AliasName) {
-#include "clang/Basic/arm_cde_builtin_aliases.inc"
- return ArmBuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
-}
-
-static bool ArmSveAliasValid(ASTContext &Context, unsigned BuiltinID,
- StringRef AliasName) {
- if (Context.BuiltinInfo.isAuxBuiltinID(BuiltinID))
- BuiltinID = Context.BuiltinInfo.getAuxBuiltinID(BuiltinID);
- return BuiltinID >= AArch64::FirstSVEBuiltin &&
- BuiltinID <= AArch64::LastSVEBuiltin;
-}
-
-static bool ArmSmeAliasValid(ASTContext &Context, unsigned BuiltinID,
- StringRef AliasName) {
- if (Context.BuiltinInfo.isAuxBuiltinID(BuiltinID))
- BuiltinID = Context.BuiltinInfo.getAuxBuiltinID(BuiltinID);
- return BuiltinID >= AArch64::FirstSMEBuiltin &&
- BuiltinID <= AArch64::LastSMEBuiltin;
-}
-
-static void handleArmBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+static void handleBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!AL.isArgIdent(0)) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
<< AL << 1 << AANT_ArgumentIdentifier;
@@ -5898,48 +5273,33 @@ static void handleArmBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef AliasName = cast<FunctionDecl>(D)->getIdentifier()->getName();
bool IsAArch64 = S.Context.getTargetInfo().getTriple().isAArch64();
- if ((IsAArch64 && !ArmSveAliasValid(S.Context, BuiltinID, AliasName) &&
- !ArmSmeAliasValid(S.Context, BuiltinID, AliasName)) ||
- (!IsAArch64 && !ArmMveAliasValid(BuiltinID, AliasName) &&
- !ArmCdeAliasValid(BuiltinID, AliasName))) {
- S.Diag(AL.getLoc(), diag::err_attribute_arm_builtin_alias);
+ bool IsARM = S.Context.getTargetInfo().getTriple().isARM();
+ bool IsRISCV = S.Context.getTargetInfo().getTriple().isRISCV();
+ bool IsHLSL = S.Context.getLangOpts().HLSL;
+ if ((IsAArch64 && !S.ARM().SveAliasValid(BuiltinID, AliasName)) ||
+ (IsARM && !S.ARM().MveAliasValid(BuiltinID, AliasName) &&
+ !S.ARM().CdeAliasValid(BuiltinID, AliasName)) ||
+ (IsRISCV && !S.RISCV().isAliasValid(BuiltinID, AliasName)) ||
+ (!IsAArch64 && !IsARM && !IsRISCV && !IsHLSL)) {
+ S.Diag(AL.getLoc(), diag::err_attribute_builtin_alias) << AL;
return;
}
- D->addAttr(::new (S.Context) ArmBuiltinAliasAttr(S.Context, AL, Ident));
-}
-
-static bool RISCVAliasValid(unsigned BuiltinID, StringRef AliasName) {
- return BuiltinID >= RISCV::FirstRVVBuiltin &&
- BuiltinID <= RISCV::LastRVVBuiltin;
+ D->addAttr(::new (S.Context) BuiltinAliasAttr(S.Context, AL, Ident));
}
-static void handleBuiltinAliasAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- if (!AL.isArgIdent(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
- << AL << 1 << AANT_ArgumentIdentifier;
+static void handleNullableTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (AL.isUsedAsTypeAttr())
return;
- }
- IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident;
- unsigned BuiltinID = Ident->getBuiltinID();
- StringRef AliasName = cast<FunctionDecl>(D)->getIdentifier()->getName();
-
- bool IsAArch64 = S.Context.getTargetInfo().getTriple().isAArch64();
- bool IsARM = S.Context.getTargetInfo().getTriple().isARM();
- bool IsRISCV = S.Context.getTargetInfo().getTriple().isRISCV();
- bool IsHLSL = S.Context.getLangOpts().HLSL;
- if ((IsAArch64 && !ArmSveAliasValid(S.Context, BuiltinID, AliasName)) ||
- (IsARM && !ArmMveAliasValid(BuiltinID, AliasName) &&
- !ArmCdeAliasValid(BuiltinID, AliasName)) ||
- (IsRISCV && !RISCVAliasValid(BuiltinID, AliasName)) ||
- (!IsAArch64 && !IsARM && !IsRISCV && !IsHLSL)) {
- S.Diag(AL.getLoc(), diag::err_attribute_builtin_alias) << AL;
+ if (auto *CRD = dyn_cast<CXXRecordDecl>(D);
+ !CRD || !(CRD->isClass() || CRD->isStruct())) {
+ S.Diag(AL.getRange().getBegin(), diag::err_attribute_wrong_decl_type_str)
+ << AL << AL.isRegularKeywordAttribute() << "classes";
return;
}
- D->addAttr(::new (S.Context) BuiltinAliasAttr(S.Context, AL, Ident));
+ handleSimpleAttribute<TypeNullableAttr>(S, D, AL);
}
static void handlePreferredTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5958,1114 +5318,6 @@ static void handlePreferredTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
//===----------------------------------------------------------------------===//
-// Checker-specific attribute handlers.
-//===----------------------------------------------------------------------===//
-static bool isValidSubjectOfNSReturnsRetainedAttribute(QualType QT) {
- return QT->isDependentType() || QT->isObjCRetainableType();
-}
-
-static bool isValidSubjectOfNSAttribute(QualType QT) {
- return QT->isDependentType() || QT->isObjCObjectPointerType() ||
- QT->isObjCNSObjectType();
-}
-
-static bool isValidSubjectOfCFAttribute(QualType QT) {
- return QT->isDependentType() || QT->isPointerType() ||
- isValidSubjectOfNSAttribute(QT);
-}
-
-static bool isValidSubjectOfOSAttribute(QualType QT) {
- if (QT->isDependentType())
- return true;
- QualType PT = QT->getPointeeType();
- return !PT.isNull() && PT->getAsCXXRecordDecl() != nullptr;
-}
-
-void Sema::AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI,
- RetainOwnershipKind K,
- bool IsTemplateInstantiation) {
- ValueDecl *VD = cast<ValueDecl>(D);
- switch (K) {
- case RetainOwnershipKind::OS:
- handleSimpleAttributeOrDiagnose<OSConsumedAttr>(
- *this, VD, CI, isValidSubjectOfOSAttribute(VD->getType()),
- diag::warn_ns_attribute_wrong_parameter_type,
- /*ExtraArgs=*/CI.getRange(), "os_consumed", /*pointers*/ 1);
- return;
- case RetainOwnershipKind::NS:
- handleSimpleAttributeOrDiagnose<NSConsumedAttr>(
- *this, VD, CI, isValidSubjectOfNSAttribute(VD->getType()),
-
- // These attributes are normally just advisory, but in ARC, ns_consumed
- // is significant. Allow non-dependent code to contain inappropriate
- // attributes even in ARC, but require template instantiations to be
- // set up correctly.
- ((IsTemplateInstantiation && getLangOpts().ObjCAutoRefCount)
- ? diag::err_ns_attribute_wrong_parameter_type
- : diag::warn_ns_attribute_wrong_parameter_type),
- /*ExtraArgs=*/CI.getRange(), "ns_consumed", /*objc pointers*/ 0);
- return;
- case RetainOwnershipKind::CF:
- handleSimpleAttributeOrDiagnose<CFConsumedAttr>(
- *this, VD, CI, isValidSubjectOfCFAttribute(VD->getType()),
- diag::warn_ns_attribute_wrong_parameter_type,
- /*ExtraArgs=*/CI.getRange(), "cf_consumed", /*pointers*/ 1);
- return;
- }
-}
-
-static Sema::RetainOwnershipKind
-parsedAttrToRetainOwnershipKind(const ParsedAttr &AL) {
- switch (AL.getKind()) {
- case ParsedAttr::AT_CFConsumed:
- case ParsedAttr::AT_CFReturnsRetained:
- case ParsedAttr::AT_CFReturnsNotRetained:
- return Sema::RetainOwnershipKind::CF;
- case ParsedAttr::AT_OSConsumesThis:
- case ParsedAttr::AT_OSConsumed:
- case ParsedAttr::AT_OSReturnsRetained:
- case ParsedAttr::AT_OSReturnsNotRetained:
- case ParsedAttr::AT_OSReturnsRetainedOnZero:
- case ParsedAttr::AT_OSReturnsRetainedOnNonZero:
- return Sema::RetainOwnershipKind::OS;
- case ParsedAttr::AT_NSConsumesSelf:
- case ParsedAttr::AT_NSConsumed:
- case ParsedAttr::AT_NSReturnsRetained:
- case ParsedAttr::AT_NSReturnsNotRetained:
- case ParsedAttr::AT_NSReturnsAutoreleased:
- return Sema::RetainOwnershipKind::NS;
- default:
- llvm_unreachable("Wrong argument supplied");
- }
-}
-
-bool Sema::checkNSReturnsRetainedReturnType(SourceLocation Loc, QualType QT) {
- if (isValidSubjectOfNSReturnsRetainedAttribute(QT))
- return false;
-
- Diag(Loc, diag::warn_ns_attribute_wrong_return_type)
- << "'ns_returns_retained'" << 0 << 0;
- return true;
-}
-
-/// \return whether the parameter is a pointer to OSObject pointer.
-static bool isValidOSObjectOutParameter(const Decl *D) {
- const auto *PVD = dyn_cast<ParmVarDecl>(D);
- if (!PVD)
- return false;
- QualType QT = PVD->getType();
- QualType PT = QT->getPointeeType();
- return !PT.isNull() && isValidSubjectOfOSAttribute(PT);
-}
-
-static void handleXReturnsXRetainedAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- QualType ReturnType;
- Sema::RetainOwnershipKind K = parsedAttrToRetainOwnershipKind(AL);
-
- if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
- ReturnType = MD->getReturnType();
- } else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) &&
- (AL.getKind() == ParsedAttr::AT_NSReturnsRetained)) {
- return; // ignore: was handled as a type attribute
- } else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) {
- ReturnType = PD->getType();
- } else if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- ReturnType = FD->getReturnType();
- } else if (const auto *Param = dyn_cast<ParmVarDecl>(D)) {
- // Attributes on parameters are used for out-parameters,
- // passed as pointers-to-pointers.
- unsigned DiagID = K == Sema::RetainOwnershipKind::CF
- ? /*pointer-to-CF-pointer*/2
- : /*pointer-to-OSObject-pointer*/3;
- ReturnType = Param->getType()->getPointeeType();
- if (ReturnType.isNull()) {
- S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_parameter_type)
- << AL << DiagID << AL.getRange();
- return;
- }
- } else if (AL.isUsedAsTypeAttr()) {
- return;
- } else {
- AttributeDeclKind ExpectedDeclKind;
- switch (AL.getKind()) {
- default: llvm_unreachable("invalid ownership attribute");
- case ParsedAttr::AT_NSReturnsRetained:
- case ParsedAttr::AT_NSReturnsAutoreleased:
- case ParsedAttr::AT_NSReturnsNotRetained:
- ExpectedDeclKind = ExpectedFunctionOrMethod;
- break;
-
- case ParsedAttr::AT_OSReturnsRetained:
- case ParsedAttr::AT_OSReturnsNotRetained:
- case ParsedAttr::AT_CFReturnsRetained:
- case ParsedAttr::AT_CFReturnsNotRetained:
- ExpectedDeclKind = ExpectedFunctionMethodOrParameter;
- break;
- }
- S.Diag(D->getBeginLoc(), diag::warn_attribute_wrong_decl_type)
- << AL.getRange() << AL << AL.isRegularKeywordAttribute()
- << ExpectedDeclKind;
- return;
- }
-
- bool TypeOK;
- bool Cf;
- unsigned ParmDiagID = 2; // Pointer-to-CF-pointer
- switch (AL.getKind()) {
- default: llvm_unreachable("invalid ownership attribute");
- case ParsedAttr::AT_NSReturnsRetained:
- TypeOK = isValidSubjectOfNSReturnsRetainedAttribute(ReturnType);
- Cf = false;
- break;
-
- case ParsedAttr::AT_NSReturnsAutoreleased:
- case ParsedAttr::AT_NSReturnsNotRetained:
- TypeOK = isValidSubjectOfNSAttribute(ReturnType);
- Cf = false;
- break;
-
- case ParsedAttr::AT_CFReturnsRetained:
- case ParsedAttr::AT_CFReturnsNotRetained:
- TypeOK = isValidSubjectOfCFAttribute(ReturnType);
- Cf = true;
- break;
-
- case ParsedAttr::AT_OSReturnsRetained:
- case ParsedAttr::AT_OSReturnsNotRetained:
- TypeOK = isValidSubjectOfOSAttribute(ReturnType);
- Cf = true;
- ParmDiagID = 3; // Pointer-to-OSObject-pointer
- break;
- }
-
- if (!TypeOK) {
- if (AL.isUsedAsTypeAttr())
- return;
-
- if (isa<ParmVarDecl>(D)) {
- S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_parameter_type)
- << AL << ParmDiagID << AL.getRange();
- } else {
- // Needs to be kept in sync with warn_ns_attribute_wrong_return_type.
- enum : unsigned {
- Function,
- Method,
- Property
- } SubjectKind = Function;
- if (isa<ObjCMethodDecl>(D))
- SubjectKind = Method;
- else if (isa<ObjCPropertyDecl>(D))
- SubjectKind = Property;
- S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_return_type)
- << AL << SubjectKind << Cf << AL.getRange();
- }
- return;
- }
-
- switch (AL.getKind()) {
- default:
- llvm_unreachable("invalid ownership attribute");
- case ParsedAttr::AT_NSReturnsAutoreleased:
- handleSimpleAttribute<NSReturnsAutoreleasedAttr>(S, D, AL);
- return;
- case ParsedAttr::AT_CFReturnsNotRetained:
- handleSimpleAttribute<CFReturnsNotRetainedAttr>(S, D, AL);
- return;
- case ParsedAttr::AT_NSReturnsNotRetained:
- handleSimpleAttribute<NSReturnsNotRetainedAttr>(S, D, AL);
- return;
- case ParsedAttr::AT_CFReturnsRetained:
- handleSimpleAttribute<CFReturnsRetainedAttr>(S, D, AL);
- return;
- case ParsedAttr::AT_NSReturnsRetained:
- handleSimpleAttribute<NSReturnsRetainedAttr>(S, D, AL);
- return;
- case ParsedAttr::AT_OSReturnsRetained:
- handleSimpleAttribute<OSReturnsRetainedAttr>(S, D, AL);
- return;
- case ParsedAttr::AT_OSReturnsNotRetained:
- handleSimpleAttribute<OSReturnsNotRetainedAttr>(S, D, AL);
- return;
- };
-}
-
-static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
- const ParsedAttr &Attrs) {
- const int EP_ObjCMethod = 1;
- const int EP_ObjCProperty = 2;
-
- SourceLocation loc = Attrs.getLoc();
- QualType resultType;
- if (isa<ObjCMethodDecl>(D))
- resultType = cast<ObjCMethodDecl>(D)->getReturnType();
- else
- resultType = cast<ObjCPropertyDecl>(D)->getType();
-
- if (!resultType->isReferenceType() &&
- (!resultType->isPointerType() || resultType->isObjCRetainableType())) {
- S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_return_type)
- << SourceRange(loc) << Attrs
- << (isa<ObjCMethodDecl>(D) ? EP_ObjCMethod : EP_ObjCProperty)
- << /*non-retainable pointer*/ 2;
-
- // Drop the attribute.
- return;
- }
-
- D->addAttr(::new (S.Context) ObjCReturnsInnerPointerAttr(S.Context, Attrs));
-}
-
-static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
- const ParsedAttr &Attrs) {
- const auto *Method = cast<ObjCMethodDecl>(D);
-
- const DeclContext *DC = Method->getDeclContext();
- if (const auto *PDecl = dyn_cast_if_present<ObjCProtocolDecl>(DC)) {
- S.Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol) << Attrs
- << 0;
- S.Diag(PDecl->getLocation(), diag::note_protocol_decl);
- return;
- }
- if (Method->getMethodFamily() == OMF_dealloc) {
- S.Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol) << Attrs
- << 1;
- return;
- }
-
- D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(S.Context, Attrs));
-}
-
-static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &Attr) {
- if (!isa<TagDecl>(D)) {
- S.Diag(D->getBeginLoc(), diag::err_nserrordomain_invalid_decl) << 0;
- return;
- }
-
- IdentifierLoc *IdentLoc =
- Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr;
- if (!IdentLoc || !IdentLoc->Ident) {
- // Try to locate the argument directly.
- SourceLocation Loc = Attr.getLoc();
- if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0))
- Loc = Attr.getArgAsExpr(0)->getBeginLoc();
-
- S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0;
- return;
- }
-
- // Verify that the identifier is a valid decl in the C decl namespace.
- LookupResult Result(S, DeclarationName(IdentLoc->Ident), SourceLocation(),
- Sema::LookupNameKind::LookupOrdinaryName);
- if (!S.LookupName(Result, S.TUScope) || !Result.getAsSingle<VarDecl>()) {
- S.Diag(IdentLoc->Loc, diag::err_nserrordomain_invalid_decl)
- << 1 << IdentLoc->Ident;
- return;
- }
-
- D->addAttr(::new (S.Context)
- NSErrorDomainAttr(S.Context, Attr, IdentLoc->Ident));
-}
-
-static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr;
-
- if (!Parm) {
- S.Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0;
- return;
- }
-
- // Typedefs only allow objc_bridge(id) and have some additional checking.
- if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
- if (!Parm->Ident->isStr("id")) {
- S.Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_id) << AL;
- return;
- }
-
- // Only allow 'cv void *'.
- QualType T = TD->getUnderlyingType();
- if (!T->isVoidPointerType()) {
- S.Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_void_pointer);
- return;
- }
- }
-
- D->addAttr(::new (S.Context) ObjCBridgeAttr(S.Context, AL, Parm->Ident));
-}
-
-static void handleObjCBridgeMutableAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr;
-
- if (!Parm) {
- S.Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0;
- return;
- }
-
- D->addAttr(::new (S.Context)
- ObjCBridgeMutableAttr(S.Context, AL, Parm->Ident));
-}
-
-static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- IdentifierInfo *RelatedClass =
- AL.isArgIdent(0) ? AL.getArgAsIdent(0)->Ident : nullptr;
- if (!RelatedClass) {
- S.Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0;
- return;
- }
- IdentifierInfo *ClassMethod =
- AL.getArgAsIdent(1) ? AL.getArgAsIdent(1)->Ident : nullptr;
- IdentifierInfo *InstanceMethod =
- AL.getArgAsIdent(2) ? AL.getArgAsIdent(2)->Ident : nullptr;
- D->addAttr(::new (S.Context) ObjCBridgeRelatedAttr(
- S.Context, AL, RelatedClass, ClassMethod, InstanceMethod));
-}
-
-static void handleObjCDesignatedInitializer(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- DeclContext *Ctx = D->getDeclContext();
-
- // This attribute can only be applied to methods in interfaces or class
- // extensions.
- if (!isa<ObjCInterfaceDecl>(Ctx) &&
- !(isa<ObjCCategoryDecl>(Ctx) &&
- cast<ObjCCategoryDecl>(Ctx)->IsClassExtension())) {
- S.Diag(D->getLocation(), diag::err_designated_init_attr_non_init);
- return;
- }
-
- ObjCInterfaceDecl *IFace;
- if (auto *CatDecl = dyn_cast<ObjCCategoryDecl>(Ctx))
- IFace = CatDecl->getClassInterface();
- else
- IFace = cast<ObjCInterfaceDecl>(Ctx);
-
- if (!IFace)
- return;
-
- IFace->setHasDesignatedInitializers();
- D->addAttr(::new (S.Context) ObjCDesignatedInitializerAttr(S.Context, AL));
-}
-
-static void handleObjCRuntimeName(Sema &S, Decl *D, const ParsedAttr &AL) {
- StringRef MetaDataName;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, MetaDataName))
- return;
- D->addAttr(::new (S.Context)
- ObjCRuntimeNameAttr(S.Context, AL, MetaDataName));
-}
-
-// When a user wants to use objc_boxable with a union or struct
-// but they don't have access to the declaration (legacy/third-party code)
-// then they can 'enable' this feature with a typedef:
-// typedef struct __attribute((objc_boxable)) legacy_struct legacy_struct;
-static void handleObjCBoxable(Sema &S, Decl *D, const ParsedAttr &AL) {
- bool notify = false;
-
- auto *RD = dyn_cast<RecordDecl>(D);
- if (RD && RD->getDefinition()) {
- RD = RD->getDefinition();
- notify = true;
- }
-
- if (RD) {
- ObjCBoxableAttr *BoxableAttr =
- ::new (S.Context) ObjCBoxableAttr(S.Context, AL);
- RD->addAttr(BoxableAttr);
- if (notify) {
- // we need to notify ASTReader/ASTWriter about
- // modification of existing declaration
- if (ASTMutationListener *L = S.getASTMutationListener())
- L->AddedAttributeToRecord(BoxableAttr, RD);
- }
- }
-}
-
-static void handleObjCOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (hasDeclarator(D))
- return;
-
- S.Diag(D->getBeginLoc(), diag::err_attribute_wrong_decl_type)
- << AL.getRange() << AL << AL.isRegularKeywordAttribute()
- << ExpectedVariable;
-}
-
-static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- const auto *VD = cast<ValueDecl>(D);
- QualType QT = VD->getType();
-
- if (!QT->isDependentType() &&
- !QT->isObjCLifetimeType()) {
- S.Diag(AL.getLoc(), diag::err_objc_precise_lifetime_bad_type)
- << QT;
- return;
- }
-
- Qualifiers::ObjCLifetime Lifetime = QT.getObjCLifetime();
-
- // If we have no lifetime yet, check the lifetime we're presumably
- // going to infer.
- if (Lifetime == Qualifiers::OCL_None && !QT->isDependentType())
- Lifetime = QT->getObjCARCImplicitLifetime();
-
- switch (Lifetime) {
- case Qualifiers::OCL_None:
- assert(QT->isDependentType() &&
- "didn't infer lifetime for non-dependent type?");
- break;
-
- case Qualifiers::OCL_Weak: // meaningful
- case Qualifiers::OCL_Strong: // meaningful
- break;
-
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Autoreleasing:
- S.Diag(AL.getLoc(), diag::warn_objc_precise_lifetime_meaningless)
- << (Lifetime == Qualifiers::OCL_Autoreleasing);
- break;
- }
-
- D->addAttr(::new (S.Context) ObjCPreciseLifetimeAttr(S.Context, AL));
-}
-
-static void handleSwiftAttrAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Make sure that there is a string literal as the annotation's single
- // argument.
- StringRef Str;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
- return;
-
- D->addAttr(::new (S.Context) SwiftAttrAttr(S.Context, AL, Str));
-}
-
-static void handleSwiftBridge(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Make sure that there is a string literal as the annotation's single
- // argument.
- StringRef BT;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, BT))
- return;
-
- // Warn about duplicate attributes if they have different arguments, but drop
- // any duplicate attributes regardless.
- if (const auto *Other = D->getAttr<SwiftBridgeAttr>()) {
- if (Other->getSwiftType() != BT)
- S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
- return;
- }
-
- D->addAttr(::new (S.Context) SwiftBridgeAttr(S.Context, AL, BT));
-}
-
-static bool isErrorParameter(Sema &S, QualType QT) {
- const auto *PT = QT->getAs<PointerType>();
- if (!PT)
- return false;
-
- QualType Pointee = PT->getPointeeType();
-
- // Check for NSError**.
- if (const auto *OPT = Pointee->getAs<ObjCObjectPointerType>())
- if (const auto *ID = OPT->getInterfaceDecl())
- if (ID->getIdentifier() == S.getNSErrorIdent())
- return true;
-
- // Check for CFError**.
- if (const auto *PT = Pointee->getAs<PointerType>())
- if (const auto *RT = PT->getPointeeType()->getAs<RecordType>())
- if (S.isCFError(RT->getDecl()))
- return true;
-
- return false;
-}
-
-static void handleSwiftError(Sema &S, Decl *D, const ParsedAttr &AL) {
- auto hasErrorParameter = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool {
- for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); I != E; ++I) {
- if (isErrorParameter(S, getFunctionOrMethodParamType(D, I)))
- return true;
- }
-
- S.Diag(AL.getLoc(), diag::err_attr_swift_error_no_error_parameter)
- << AL << isa<ObjCMethodDecl>(D);
- return false;
- };
-
- auto hasPointerResult = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool {
- // - C, ObjC, and block pointers are definitely okay.
- // - References are definitely not okay.
- // - nullptr_t is weird, but acceptable.
- QualType RT = getFunctionOrMethodResultType(D);
- if (RT->hasPointerRepresentation() && !RT->isReferenceType())
- return true;
-
- S.Diag(AL.getLoc(), diag::err_attr_swift_error_return_type)
- << AL << AL.getArgAsIdent(0)->Ident->getName() << isa<ObjCMethodDecl>(D)
- << /*pointer*/ 1;
- return false;
- };
-
- auto hasIntegerResult = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool {
- QualType RT = getFunctionOrMethodResultType(D);
- if (RT->isIntegralType(S.Context))
- return true;
-
- S.Diag(AL.getLoc(), diag::err_attr_swift_error_return_type)
- << AL << AL.getArgAsIdent(0)->Ident->getName() << isa<ObjCMethodDecl>(D)
- << /*integral*/ 0;
- return false;
- };
-
- if (D->isInvalidDecl())
- return;
-
- IdentifierLoc *Loc = AL.getArgAsIdent(0);
- SwiftErrorAttr::ConventionKind Convention;
- if (!SwiftErrorAttr::ConvertStrToConventionKind(Loc->Ident->getName(),
- Convention)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
- << AL << Loc->Ident;
- return;
- }
-
- switch (Convention) {
- case SwiftErrorAttr::None:
- // No additional validation required.
- break;
-
- case SwiftErrorAttr::NonNullError:
- if (!hasErrorParameter(S, D, AL))
- return;
- break;
-
- case SwiftErrorAttr::NullResult:
- if (!hasErrorParameter(S, D, AL) || !hasPointerResult(S, D, AL))
- return;
- break;
-
- case SwiftErrorAttr::NonZeroResult:
- case SwiftErrorAttr::ZeroResult:
- if (!hasErrorParameter(S, D, AL) || !hasIntegerResult(S, D, AL))
- return;
- break;
- }
-
- D->addAttr(::new (S.Context) SwiftErrorAttr(S.Context, AL, Convention));
-}
-
-static void checkSwiftAsyncErrorBlock(Sema &S, Decl *D,
- const SwiftAsyncErrorAttr *ErrorAttr,
- const SwiftAsyncAttr *AsyncAttr) {
- if (AsyncAttr->getKind() == SwiftAsyncAttr::None) {
- if (ErrorAttr->getConvention() != SwiftAsyncErrorAttr::None) {
- S.Diag(AsyncAttr->getLocation(),
- diag::err_swift_async_error_without_swift_async)
- << AsyncAttr << isa<ObjCMethodDecl>(D);
- }
- return;
- }
-
- const ParmVarDecl *HandlerParam = getFunctionOrMethodParam(
- D, AsyncAttr->getCompletionHandlerIndex().getASTIndex());
- // handleSwiftAsyncAttr already verified the type is correct, so no need to
- // double-check it here.
- const auto *FuncTy = HandlerParam->getType()
- ->castAs<BlockPointerType>()
- ->getPointeeType()
- ->getAs<FunctionProtoType>();
- ArrayRef<QualType> BlockParams;
- if (FuncTy)
- BlockParams = FuncTy->getParamTypes();
-
- switch (ErrorAttr->getConvention()) {
- case SwiftAsyncErrorAttr::ZeroArgument:
- case SwiftAsyncErrorAttr::NonZeroArgument: {
- uint32_t ParamIdx = ErrorAttr->getHandlerParamIdx();
- if (ParamIdx == 0 || ParamIdx > BlockParams.size()) {
- S.Diag(ErrorAttr->getLocation(),
- diag::err_attribute_argument_out_of_bounds) << ErrorAttr << 2;
- return;
- }
- QualType ErrorParam = BlockParams[ParamIdx - 1];
- if (!ErrorParam->isIntegralType(S.Context)) {
- StringRef ConvStr =
- ErrorAttr->getConvention() == SwiftAsyncErrorAttr::ZeroArgument
- ? "zero_argument"
- : "nonzero_argument";
- S.Diag(ErrorAttr->getLocation(), diag::err_swift_async_error_non_integral)
- << ErrorAttr << ConvStr << ParamIdx << ErrorParam;
- return;
- }
- break;
- }
- case SwiftAsyncErrorAttr::NonNullError: {
- bool AnyErrorParams = false;
- for (QualType Param : BlockParams) {
- // Check for NSError *.
- if (const auto *ObjCPtrTy = Param->getAs<ObjCObjectPointerType>()) {
- if (const auto *ID = ObjCPtrTy->getInterfaceDecl()) {
- if (ID->getIdentifier() == S.getNSErrorIdent()) {
- AnyErrorParams = true;
- break;
- }
- }
- }
- // Check for CFError *.
- if (const auto *PtrTy = Param->getAs<PointerType>()) {
- if (const auto *RT = PtrTy->getPointeeType()->getAs<RecordType>()) {
- if (S.isCFError(RT->getDecl())) {
- AnyErrorParams = true;
- break;
- }
- }
- }
- }
-
- if (!AnyErrorParams) {
- S.Diag(ErrorAttr->getLocation(),
- diag::err_swift_async_error_no_error_parameter)
- << ErrorAttr << isa<ObjCMethodDecl>(D);
- return;
- }
- break;
- }
- case SwiftAsyncErrorAttr::None:
- break;
- }
-}
-
-static void handleSwiftAsyncError(Sema &S, Decl *D, const ParsedAttr &AL) {
- IdentifierLoc *IDLoc = AL.getArgAsIdent(0);
- SwiftAsyncErrorAttr::ConventionKind ConvKind;
- if (!SwiftAsyncErrorAttr::ConvertStrToConventionKind(IDLoc->Ident->getName(),
- ConvKind)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
- << AL << IDLoc->Ident;
- return;
- }
-
- uint32_t ParamIdx = 0;
- switch (ConvKind) {
- case SwiftAsyncErrorAttr::ZeroArgument:
- case SwiftAsyncErrorAttr::NonZeroArgument: {
- if (!AL.checkExactlyNumArgs(S, 2))
- return;
-
- Expr *IdxExpr = AL.getArgAsExpr(1);
- if (!checkUInt32Argument(S, AL, IdxExpr, ParamIdx))
- return;
- break;
- }
- case SwiftAsyncErrorAttr::NonNullError:
- case SwiftAsyncErrorAttr::None: {
- if (!AL.checkExactlyNumArgs(S, 1))
- return;
- break;
- }
- }
-
- auto *ErrorAttr =
- ::new (S.Context) SwiftAsyncErrorAttr(S.Context, AL, ConvKind, ParamIdx);
- D->addAttr(ErrorAttr);
-
- if (auto *AsyncAttr = D->getAttr<SwiftAsyncAttr>())
- checkSwiftAsyncErrorBlock(S, D, ErrorAttr, AsyncAttr);
-}
-
-// For a function, this will validate a compound Swift name, e.g.
-// <code>init(foo:bar:baz:)</code> or <code>controllerForName(_:)</code>, and
-// the function will output the number of parameter names, and whether this is a
-// single-arg initializer.
-//
-// For a type, enum constant, property, or variable declaration, this will
-// validate either a simple identifier, or a qualified
-// <code>context.identifier</code> name.
-static bool
-validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, SourceLocation Loc,
- StringRef Name, unsigned &SwiftParamCount,
- bool &IsSingleParamInit) {
- SwiftParamCount = 0;
- IsSingleParamInit = false;
-
- // Check whether this will be mapped to a getter or setter of a property.
- bool IsGetter = false, IsSetter = false;
- if (Name.starts_with("getter:")) {
- IsGetter = true;
- Name = Name.substr(7);
- } else if (Name.starts_with("setter:")) {
- IsSetter = true;
- Name = Name.substr(7);
- }
-
- if (Name.back() != ')') {
- S.Diag(Loc, diag::warn_attr_swift_name_function) << AL;
- return false;
- }
-
- bool IsMember = false;
- StringRef ContextName, BaseName, Parameters;
-
- std::tie(BaseName, Parameters) = Name.split('(');
-
- // Split at the first '.', if it exists, which separates the context name
- // from the base name.
- std::tie(ContextName, BaseName) = BaseName.split('.');
- if (BaseName.empty()) {
- BaseName = ContextName;
- ContextName = StringRef();
- } else if (ContextName.empty() || !isValidAsciiIdentifier(ContextName)) {
- S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier)
- << AL << /*context*/ 1;
- return false;
- } else {
- IsMember = true;
- }
-
- if (!isValidAsciiIdentifier(BaseName) || BaseName == "_") {
- S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier)
- << AL << /*basename*/ 0;
- return false;
- }
-
- bool IsSubscript = BaseName == "subscript";
- // A subscript accessor must be a getter or setter.
- if (IsSubscript && !IsGetter && !IsSetter) {
- S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter)
- << AL << /* getter or setter */ 0;
- return false;
- }
-
- if (Parameters.empty()) {
- S.Diag(Loc, diag::warn_attr_swift_name_missing_parameters) << AL;
- return false;
- }
-
- assert(Parameters.back() == ')' && "expected ')'");
- Parameters = Parameters.drop_back(); // ')'
-
- if (Parameters.empty()) {
- // Setters and subscripts must have at least one parameter.
- if (IsSubscript) {
- S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter)
- << AL << /* have at least one parameter */1;
- return false;
- }
-
- if (IsSetter) {
- S.Diag(Loc, diag::warn_attr_swift_name_setter_parameters) << AL;
- return false;
- }
-
- return true;
- }
-
- if (Parameters.back() != ':') {
- S.Diag(Loc, diag::warn_attr_swift_name_function) << AL;
- return false;
- }
-
- StringRef CurrentParam;
- std::optional<unsigned> SelfLocation;
- unsigned NewValueCount = 0;
- std::optional<unsigned> NewValueLocation;
- do {
- std::tie(CurrentParam, Parameters) = Parameters.split(':');
-
- if (!isValidAsciiIdentifier(CurrentParam)) {
- S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier)
- << AL << /*parameter*/2;
- return false;
- }
-
- if (IsMember && CurrentParam == "self") {
- // "self" indicates the "self" argument for a member.
-
- // More than one "self"?
- if (SelfLocation) {
- S.Diag(Loc, diag::warn_attr_swift_name_multiple_selfs) << AL;
- return false;
- }
-
- // The "self" location is the current parameter.
- SelfLocation = SwiftParamCount;
- } else if (CurrentParam == "newValue") {
- // "newValue" indicates the "newValue" argument for a setter.
-
- // There should only be one 'newValue', but it's only significant for
- // subscript accessors, so don't error right away.
- ++NewValueCount;
-
- NewValueLocation = SwiftParamCount;
- }
-
- ++SwiftParamCount;
- } while (!Parameters.empty());
-
- // Only instance subscripts are currently supported.
- if (IsSubscript && !SelfLocation) {
- S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter)
- << AL << /*have a 'self:' parameter*/2;
- return false;
- }
-
- IsSingleParamInit =
- SwiftParamCount == 1 && BaseName == "init" && CurrentParam != "_";
-
- // Check the number of parameters for a getter/setter.
- if (IsGetter || IsSetter) {
- // Setters have one parameter for the new value.
- unsigned NumExpectedParams = IsGetter ? 0 : 1;
- unsigned ParamDiag =
- IsGetter ? diag::warn_attr_swift_name_getter_parameters
- : diag::warn_attr_swift_name_setter_parameters;
-
- // Instance methods have one parameter for "self".
- if (SelfLocation)
- ++NumExpectedParams;
-
- // Subscripts may have additional parameters beyond the expected params for
- // the index.
- if (IsSubscript) {
- if (SwiftParamCount < NumExpectedParams) {
- S.Diag(Loc, ParamDiag) << AL;
- return false;
- }
-
- // A subscript setter must explicitly label its newValue parameter to
- // distinguish it from index parameters.
- if (IsSetter) {
- if (!NewValueLocation) {
- S.Diag(Loc, diag::warn_attr_swift_name_subscript_setter_no_newValue)
- << AL;
- return false;
- }
- if (NewValueCount > 1) {
- S.Diag(Loc, diag::warn_attr_swift_name_subscript_setter_multiple_newValues)
- << AL;
- return false;
- }
- } else {
- // Subscript getters should have no 'newValue:' parameter.
- if (NewValueLocation) {
- S.Diag(Loc, diag::warn_attr_swift_name_subscript_getter_newValue)
- << AL;
- return false;
- }
- }
- } else {
- // Property accessors must have exactly the number of expected params.
- if (SwiftParamCount != NumExpectedParams) {
- S.Diag(Loc, ParamDiag) << AL;
- return false;
- }
- }
- }
-
- return true;
-}
-
-bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc,
- const ParsedAttr &AL, bool IsAsync) {
- if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) {
- ArrayRef<ParmVarDecl*> Params;
- unsigned ParamCount;
-
- if (const auto *Method = dyn_cast<ObjCMethodDecl>(D)) {
- ParamCount = Method->getSelector().getNumArgs();
- Params = Method->parameters().slice(0, ParamCount);
- } else {
- const auto *F = cast<FunctionDecl>(D);
-
- ParamCount = F->getNumParams();
- Params = F->parameters();
-
- if (!F->hasWrittenPrototype()) {
- Diag(Loc, diag::warn_attribute_wrong_decl_type)
- << AL << AL.isRegularKeywordAttribute()
- << ExpectedFunctionWithProtoType;
- return false;
- }
- }
-
- // The async name drops the last callback parameter.
- if (IsAsync) {
- if (ParamCount == 0) {
- Diag(Loc, diag::warn_attr_swift_name_decl_missing_params)
- << AL << isa<ObjCMethodDecl>(D);
- return false;
- }
- ParamCount -= 1;
- }
-
- unsigned SwiftParamCount;
- bool IsSingleParamInit;
- if (!validateSwiftFunctionName(*this, AL, Loc, Name,
- SwiftParamCount, IsSingleParamInit))
- return false;
-
- bool ParamCountValid;
- if (SwiftParamCount == ParamCount) {
- ParamCountValid = true;
- } else if (SwiftParamCount > ParamCount) {
- ParamCountValid = IsSingleParamInit && ParamCount == 0;
- } else {
- // We have fewer Swift parameters than Objective-C parameters, but that
- // might be because we've transformed some of them. Check for potential
- // "out" parameters and err on the side of not warning.
- unsigned MaybeOutParamCount =
- llvm::count_if(Params, [](const ParmVarDecl *Param) -> bool {
- QualType ParamTy = Param->getType();
- if (ParamTy->isReferenceType() || ParamTy->isPointerType())
- return !ParamTy->getPointeeType().isConstQualified();
- return false;
- });
-
- ParamCountValid = SwiftParamCount + MaybeOutParamCount >= ParamCount;
- }
-
- if (!ParamCountValid) {
- Diag(Loc, diag::warn_attr_swift_name_num_params)
- << (SwiftParamCount > ParamCount) << AL << ParamCount
- << SwiftParamCount;
- return false;
- }
- } else if ((isa<EnumConstantDecl>(D) || isa<ObjCProtocolDecl>(D) ||
- isa<ObjCInterfaceDecl>(D) || isa<ObjCPropertyDecl>(D) ||
- isa<VarDecl>(D) || isa<TypedefNameDecl>(D) || isa<TagDecl>(D) ||
- isa<IndirectFieldDecl>(D) || isa<FieldDecl>(D)) &&
- !IsAsync) {
- StringRef ContextName, BaseName;
-
- std::tie(ContextName, BaseName) = Name.split('.');
- if (BaseName.empty()) {
- BaseName = ContextName;
- ContextName = StringRef();
- } else if (!isValidAsciiIdentifier(ContextName)) {
- Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL
- << /*context*/1;
- return false;
- }
-
- if (!isValidAsciiIdentifier(BaseName)) {
- Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL
- << /*basename*/0;
- return false;
- }
- } else {
- Diag(Loc, diag::warn_attr_swift_name_decl_kind) << AL;
- return false;
- }
- return true;
-}
-
-static void handleSwiftName(Sema &S, Decl *D, const ParsedAttr &AL) {
- StringRef Name;
- SourceLocation Loc;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc))
- return;
-
- if (!S.DiagnoseSwiftName(D, Name, Loc, AL, /*IsAsync=*/false))
- return;
-
- D->addAttr(::new (S.Context) SwiftNameAttr(S.Context, AL, Name));
-}
-
-static void handleSwiftAsyncName(Sema &S, Decl *D, const ParsedAttr &AL) {
- StringRef Name;
- SourceLocation Loc;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc))
- return;
-
- if (!S.DiagnoseSwiftName(D, Name, Loc, AL, /*IsAsync=*/true))
- return;
-
- D->addAttr(::new (S.Context) SwiftAsyncNameAttr(S.Context, AL, Name));
-}
-
-static void handleSwiftNewType(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Make sure that there is an identifier as the annotation's single argument.
- if (!AL.checkExactlyNumArgs(S, 1))
- return;
-
- if (!AL.isArgIdent(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIdentifier;
- return;
- }
-
- SwiftNewTypeAttr::NewtypeKind Kind;
- IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
- if (!SwiftNewTypeAttr::ConvertStrToNewtypeKind(II->getName(), Kind)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II;
- return;
- }
-
- if (!isa<TypedefNameDecl>(D)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str)
- << AL << AL.isRegularKeywordAttribute() << "typedefs";
- return;
- }
-
- D->addAttr(::new (S.Context) SwiftNewTypeAttr(S.Context, AL, Kind));
-}
-
-static void handleSwiftAsyncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!AL.isArgIdent(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
- << AL << 1 << AANT_ArgumentIdentifier;
- return;
- }
-
- SwiftAsyncAttr::Kind Kind;
- IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
- if (!SwiftAsyncAttr::ConvertStrToKind(II->getName(), Kind)) {
- S.Diag(AL.getLoc(), diag::err_swift_async_no_access) << AL << II;
- return;
- }
-
- ParamIdx Idx;
- if (Kind == SwiftAsyncAttr::None) {
- // If this is 'none', then there shouldn't be any additional arguments.
- if (!AL.checkExactlyNumArgs(S, 1))
- return;
- } else {
- // Non-none swift_async requires a completion handler index argument.
- if (!AL.checkExactlyNumArgs(S, 2))
- return;
-
- Expr *HandlerIdx = AL.getArgAsExpr(1);
- if (!checkFunctionOrMethodParameterIndex(S, D, AL, 2, HandlerIdx, Idx))
- return;
-
- const ParmVarDecl *CompletionBlock =
- getFunctionOrMethodParam(D, Idx.getASTIndex());
- QualType CompletionBlockType = CompletionBlock->getType();
- if (!CompletionBlockType->isBlockPointerType()) {
- S.Diag(CompletionBlock->getLocation(),
- diag::err_swift_async_bad_block_type)
- << CompletionBlock->getType();
- return;
- }
- QualType BlockTy =
- CompletionBlockType->castAs<BlockPointerType>()->getPointeeType();
- if (!BlockTy->castAs<FunctionType>()->getReturnType()->isVoidType()) {
- S.Diag(CompletionBlock->getLocation(),
- diag::err_swift_async_bad_block_type)
- << CompletionBlock->getType();
- return;
- }
- }
-
- auto *AsyncAttr =
- ::new (S.Context) SwiftAsyncAttr(S.Context, AL, Kind, Idx);
- D->addAttr(AsyncAttr);
-
- if (auto *ErrorAttr = D->getAttr<SwiftAsyncErrorAttr>())
- checkSwiftAsyncErrorBlock(S, D, ErrorAttr, AsyncAttr);
-}
-
-//===----------------------------------------------------------------------===//
// Microsoft specific attribute handlers.
//===----------------------------------------------------------------------===//
@@ -7144,230 +5396,6 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(UA);
}
-static void handleHLSLNumThreadsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- llvm::VersionTuple SMVersion =
- S.Context.getTargetInfo().getTriple().getOSVersion();
- uint32_t ZMax = 1024;
- uint32_t ThreadMax = 1024;
- if (SMVersion.getMajor() <= 4) {
- ZMax = 1;
- ThreadMax = 768;
- } else if (SMVersion.getMajor() == 5) {
- ZMax = 64;
- ThreadMax = 1024;
- }
-
- uint32_t X;
- if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), X))
- return;
- if (X > 1024) {
- S.Diag(AL.getArgAsExpr(0)->getExprLoc(),
- diag::err_hlsl_numthreads_argument_oor) << 0 << 1024;
- return;
- }
- uint32_t Y;
- if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(1), Y))
- return;
- if (Y > 1024) {
- S.Diag(AL.getArgAsExpr(1)->getExprLoc(),
- diag::err_hlsl_numthreads_argument_oor) << 1 << 1024;
- return;
- }
- uint32_t Z;
- if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(2), Z))
- return;
- if (Z > ZMax) {
- S.Diag(AL.getArgAsExpr(2)->getExprLoc(),
- diag::err_hlsl_numthreads_argument_oor) << 2 << ZMax;
- return;
- }
-
- if (X * Y * Z > ThreadMax) {
- S.Diag(AL.getLoc(), diag::err_hlsl_numthreads_invalid) << ThreadMax;
- return;
- }
-
- HLSLNumThreadsAttr *NewAttr = S.mergeHLSLNumThreadsAttr(D, AL, X, Y, Z);
- if (NewAttr)
- D->addAttr(NewAttr);
-}
-
-HLSLNumThreadsAttr *Sema::mergeHLSLNumThreadsAttr(Decl *D,
- const AttributeCommonInfo &AL,
- int X, int Y, int Z) {
- if (HLSLNumThreadsAttr *NT = D->getAttr<HLSLNumThreadsAttr>()) {
- if (NT->getX() != X || NT->getY() != Y || NT->getZ() != Z) {
- Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
- Diag(AL.getLoc(), diag::note_conflicting_attribute);
- }
- return nullptr;
- }
- return ::new (Context) HLSLNumThreadsAttr(Context, AL, X, Y, Z);
-}
-
-static bool isLegalTypeForHLSLSV_DispatchThreadID(QualType T) {
- if (!T->hasUnsignedIntegerRepresentation())
- return false;
- if (const auto *VT = T->getAs<VectorType>())
- return VT->getNumElements() <= 3;
- return true;
-}
-
-static void handleHLSLSV_DispatchThreadIDAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- // FIXME: support semantic on field.
- // See https://github.com/llvm/llvm-project/issues/57889.
- if (isa<FieldDecl>(D)) {
- S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
- << AL << "parameter";
- return;
- }
-
- auto *VD = cast<ValueDecl>(D);
- if (!isLegalTypeForHLSLSV_DispatchThreadID(VD->getType())) {
- S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
- << AL << "uint/uint2/uint3";
- return;
- }
-
- D->addAttr(::new (S.Context) HLSLSV_DispatchThreadIDAttr(S.Context, AL));
-}
-
-static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- StringRef Str;
- SourceLocation ArgLoc;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
- return;
-
- HLSLShaderAttr::ShaderType ShaderType;
- if (!HLSLShaderAttr::ConvertStrToShaderType(Str, ShaderType)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
- << AL << Str << ArgLoc;
- return;
- }
-
- // FIXME: check function match the shader stage.
-
- HLSLShaderAttr *NewAttr = S.mergeHLSLShaderAttr(D, AL, ShaderType);
- if (NewAttr)
- D->addAttr(NewAttr);
-}
-
-HLSLShaderAttr *
-Sema::mergeHLSLShaderAttr(Decl *D, const AttributeCommonInfo &AL,
- HLSLShaderAttr::ShaderType ShaderType) {
- if (HLSLShaderAttr *NT = D->getAttr<HLSLShaderAttr>()) {
- if (NT->getType() != ShaderType) {
- Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
- Diag(AL.getLoc(), diag::note_conflicting_attribute);
- }
- return nullptr;
- }
- return HLSLShaderAttr::Create(Context, ShaderType, AL);
-}
-
-static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- StringRef Space = "space0";
- StringRef Slot = "";
-
- if (!AL.isArgIdent(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIdentifier;
- return;
- }
-
- IdentifierLoc *Loc = AL.getArgAsIdent(0);
- StringRef Str = Loc->Ident->getName();
- SourceLocation ArgLoc = Loc->Loc;
-
- SourceLocation SpaceArgLoc;
- if (AL.getNumArgs() == 2) {
- Slot = Str;
- if (!AL.isArgIdent(1)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIdentifier;
- return;
- }
-
- IdentifierLoc *Loc = AL.getArgAsIdent(1);
- Space = Loc->Ident->getName();
- SpaceArgLoc = Loc->Loc;
- } else {
- Slot = Str;
- }
-
- // Validate.
- if (!Slot.empty()) {
- switch (Slot[0]) {
- case 'u':
- case 'b':
- case 's':
- case 't':
- break;
- default:
- S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_type)
- << Slot.substr(0, 1);
- return;
- }
-
- StringRef SlotNum = Slot.substr(1);
- unsigned Num = 0;
- if (SlotNum.getAsInteger(10, Num)) {
- S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_number);
- return;
- }
- }
-
- if (!Space.starts_with("space")) {
- S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
- return;
- }
- StringRef SpaceNum = Space.substr(5);
- unsigned Num = 0;
- if (SpaceNum.getAsInteger(10, Num)) {
- S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
- return;
- }
-
- // FIXME: check reg type match decl. Issue
- // https://github.com/llvm/llvm-project/issues/57886.
- HLSLResourceBindingAttr *NewAttr =
- HLSLResourceBindingAttr::Create(S.getASTContext(), Slot, Space, AL);
- if (NewAttr)
- D->addAttr(NewAttr);
-}
-
-static void handleHLSLParamModifierAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- HLSLParamModifierAttr *NewAttr = S.mergeHLSLParamModifierAttr(
- D, AL,
- static_cast<HLSLParamModifierAttr::Spelling>(AL.getSemanticSpelling()));
- if (NewAttr)
- D->addAttr(NewAttr);
-}
-
-HLSLParamModifierAttr *
-Sema::mergeHLSLParamModifierAttr(Decl *D, const AttributeCommonInfo &AL,
- HLSLParamModifierAttr::Spelling Spelling) {
- // We can only merge an `in` attribute with an `out` attribute. All other
- // combinations of duplicated attributes are ill-formed.
- if (HLSLParamModifierAttr *PA = D->getAttr<HLSLParamModifierAttr>()) {
- if ((PA->isIn() && Spelling == HLSLParamModifierAttr::Keyword_out) ||
- (PA->isOut() && Spelling == HLSLParamModifierAttr::Keyword_in)) {
- D->dropAttr<HLSLParamModifierAttr>();
- SourceRange AdjustedRange = {PA->getLocation(), AL.getRange().getEnd()};
- return HLSLParamModifierAttr::Create(
- Context, /*MergedSpelling=*/true, AdjustedRange,
- HLSLParamModifierAttr::Keyword_inout);
- }
- Diag(AL.getLoc(), diag::err_hlsl_duplicate_parameter_modifier) << AL;
- Diag(PA->getLocation(), diag::note_conflicting_attribute);
- return nullptr;
- }
- return HLSLParamModifierAttr::Create(Context, AL);
-}
-
static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!S.LangOpts.CPlusPlus) {
S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang)
@@ -7452,283 +5480,6 @@ static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
AbiTagAttr(S.Context, AL, Tags.data(), Tags.size()));
}
-static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Check the attribute arguments.
- if (AL.getNumArgs() > 1) {
- S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1;
- return;
- }
-
- StringRef Str;
- SourceLocation ArgLoc;
-
- if (AL.getNumArgs() == 0)
- Str = "";
- else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
- return;
-
- ARMInterruptAttr::InterruptType Kind;
- if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << Str
- << ArgLoc;
- return;
- }
-
- D->addAttr(::new (S.Context) ARMInterruptAttr(S.Context, AL, Kind));
-}
-
-static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // MSP430 'interrupt' attribute is applied to
- // a function with no parameters and void return type.
- if (!isFunctionOrMethod(D)) {
- S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
- << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod;
- return;
- }
-
- if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
- S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
- << /*MSP430*/ 1 << 0;
- return;
- }
-
- if (!getFunctionOrMethodResultType(D)->isVoidType()) {
- S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
- << /*MSP430*/ 1 << 1;
- return;
- }
-
- // The attribute takes one integer argument.
- if (!AL.checkExactlyNumArgs(S, 1))
- return;
-
- if (!AL.isArgExpr(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIntegerConstant;
- return;
- }
-
- Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0));
- std::optional<llvm::APSInt> NumParams = llvm::APSInt(32);
- if (!(NumParams = NumParamsExpr->getIntegerConstantExpr(S.Context))) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIntegerConstant
- << NumParamsExpr->getSourceRange();
- return;
- }
- // The argument should be in range 0..63.
- unsigned Num = NumParams->getLimitedValue(255);
- if (Num > 63) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << AL << (int)NumParams->getSExtValue()
- << NumParamsExpr->getSourceRange();
- return;
- }
-
- D->addAttr(::new (S.Context) MSP430InterruptAttr(S.Context, AL, Num));
- D->addAttr(UsedAttr::CreateImplicit(S.Context));
-}
-
-static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Only one optional argument permitted.
- if (AL.getNumArgs() > 1) {
- S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1;
- return;
- }
-
- StringRef Str;
- SourceLocation ArgLoc;
-
- if (AL.getNumArgs() == 0)
- Str = "";
- else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
- return;
-
- // Semantic checks for a function with the 'interrupt' attribute for MIPS:
- // a) Must be a function.
- // b) Must have no parameters.
- // c) Must have the 'void' return type.
- // d) Cannot have the 'mips16' attribute, as that instruction set
- // lacks the 'eret' instruction.
- // e) The attribute itself must either have no argument or one of the
- // valid interrupt types, see [MipsInterruptDocs].
-
- if (!isFunctionOrMethod(D)) {
- S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
- << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod;
- return;
- }
-
- if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
- S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
- << /*MIPS*/ 0 << 0;
- return;
- }
-
- if (!getFunctionOrMethodResultType(D)->isVoidType()) {
- S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
- << /*MIPS*/ 0 << 1;
- return;
- }
-
- // We still have to do this manually because the Interrupt attributes are
- // a bit special due to sharing their spellings across targets.
- if (checkAttrMutualExclusion<Mips16Attr>(S, D, AL))
- return;
-
- MipsInterruptAttr::InterruptType Kind;
- if (!MipsInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
- << AL << "'" + std::string(Str) + "'";
- return;
- }
-
- D->addAttr(::new (S.Context) MipsInterruptAttr(S.Context, AL, Kind));
-}
-
-static void handleM68kInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!AL.checkExactlyNumArgs(S, 1))
- return;
-
- if (!AL.isArgExpr(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIntegerConstant;
- return;
- }
-
- // FIXME: Check for decl - it should be void ()(void).
-
- Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0));
- auto MaybeNumParams = NumParamsExpr->getIntegerConstantExpr(S.Context);
- if (!MaybeNumParams) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIntegerConstant
- << NumParamsExpr->getSourceRange();
- return;
- }
-
- unsigned Num = MaybeNumParams->getLimitedValue(255);
- if ((Num & 1) || Num > 30) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << AL << (int)MaybeNumParams->getSExtValue()
- << NumParamsExpr->getSourceRange();
- return;
- }
-
- D->addAttr(::new (S.Context) M68kInterruptAttr(S.Context, AL, Num));
- D->addAttr(UsedAttr::CreateImplicit(S.Context));
-}
-
-static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Semantic checks for a function with the 'interrupt' attribute.
- // a) Must be a function.
- // b) Must have the 'void' return type.
- // c) Must take 1 or 2 arguments.
- // d) The 1st argument must be a pointer.
- // e) The 2nd argument (if any) must be an unsigned integer.
- if (!isFunctionOrMethod(D) || !hasFunctionProto(D) || isInstanceMethod(D) ||
- CXXMethodDecl::isStaticOverloadedOperator(
- cast<NamedDecl>(D)->getDeclName().getCXXOverloadedOperator())) {
- S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
- << AL << AL.isRegularKeywordAttribute()
- << ExpectedFunctionWithProtoType;
- return;
- }
- // Interrupt handler must have void return type.
- if (!getFunctionOrMethodResultType(D)->isVoidType()) {
- S.Diag(getFunctionOrMethodResultSourceRange(D).getBegin(),
- diag::err_anyx86_interrupt_attribute)
- << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
- ? 0
- : 1)
- << 0;
- return;
- }
- // Interrupt handler must have 1 or 2 parameters.
- unsigned NumParams = getFunctionOrMethodNumParams(D);
- if (NumParams < 1 || NumParams > 2) {
- S.Diag(D->getBeginLoc(), diag::err_anyx86_interrupt_attribute)
- << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
- ? 0
- : 1)
- << 1;
- return;
- }
- // The first argument must be a pointer.
- if (!getFunctionOrMethodParamType(D, 0)->isPointerType()) {
- S.Diag(getFunctionOrMethodParamRange(D, 0).getBegin(),
- diag::err_anyx86_interrupt_attribute)
- << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
- ? 0
- : 1)
- << 2;
- return;
- }
- // The second argument, if present, must be an unsigned integer.
- unsigned TypeSize =
- S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64
- ? 64
- : 32;
- if (NumParams == 2 &&
- (!getFunctionOrMethodParamType(D, 1)->isUnsignedIntegerType() ||
- S.Context.getTypeSize(getFunctionOrMethodParamType(D, 1)) != TypeSize)) {
- S.Diag(getFunctionOrMethodParamRange(D, 1).getBegin(),
- diag::err_anyx86_interrupt_attribute)
- << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
- ? 0
- : 1)
- << 3 << S.Context.getIntTypeForBitwidth(TypeSize, /*Signed=*/false);
- return;
- }
- D->addAttr(::new (S.Context) AnyX86InterruptAttr(S.Context, AL));
- D->addAttr(UsedAttr::CreateImplicit(S.Context));
-}
-
-static void handleAVRInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!isFunctionOrMethod(D)) {
- S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
- << AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
- return;
- }
-
- if (!AL.checkExactlyNumArgs(S, 0))
- return;
-
- handleSimpleAttribute<AVRInterruptAttr>(S, D, AL);
-}
-
-static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!isFunctionOrMethod(D)) {
- S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
- << AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
- return;
- }
-
- if (!AL.checkExactlyNumArgs(S, 0))
- return;
-
- handleSimpleAttribute<AVRSignalAttr>(S, D, AL);
-}
-
-static void handleBPFPreserveAIRecord(Sema &S, RecordDecl *RD) {
- // Add preserve_access_index attribute to all fields and inner records.
- for (auto *D : RD->decls()) {
- if (D->hasAttr<BPFPreserveAccessIndexAttr>())
- continue;
-
- D->addAttr(BPFPreserveAccessIndexAttr::CreateImplicit(S.Context));
- if (auto *Rec = dyn_cast<RecordDecl>(D))
- handleBPFPreserveAIRecord(S, Rec);
- }
-}
-
-static void handleBPFPreserveAccessIndexAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- auto *Rec = cast<RecordDecl>(D);
- handleBPFPreserveAIRecord(S, Rec);
- Rec->addAttr(::new (S.Context) BPFPreserveAccessIndexAttr(S.Context, AL));
-}
-
static bool hasBTFDeclTagAttr(Decl *D, StringRef Tag) {
for (const auto *I : D->specific_attrs<BTFDeclTagAttr>()) {
if (I->getBTFDeclTag() == Tag)
@@ -7753,352 +5504,40 @@ BTFDeclTagAttr *Sema::mergeBTFDeclTagAttr(Decl *D, const BTFDeclTagAttr &AL) {
return ::new (Context) BTFDeclTagAttr(Context, AL, AL.getBTFDeclTag());
}
-static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- if (!isFunctionOrMethod(D)) {
- S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
- << AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
- return;
- }
-
- auto *FD = cast<FunctionDecl>(D);
- if (FD->isThisDeclarationADefinition()) {
- S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
- return;
- }
-
- StringRef Str;
- SourceLocation ArgLoc;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
- return;
-
- D->addAttr(::new (S.Context) WebAssemblyExportNameAttr(S.Context, AL, Str));
- D->addAttr(UsedAttr::CreateImplicit(S.Context));
-}
-
-WebAssemblyImportModuleAttr *
-Sema::mergeImportModuleAttr(Decl *D, const WebAssemblyImportModuleAttr &AL) {
- auto *FD = cast<FunctionDecl>(D);
-
- if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
- if (ExistingAttr->getImportModule() == AL.getImportModule())
- return nullptr;
- Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) << 0
- << ExistingAttr->getImportModule() << AL.getImportModule();
- Diag(AL.getLoc(), diag::note_previous_attribute);
- return nullptr;
- }
- if (FD->hasBody()) {
- Diag(AL.getLoc(), diag::warn_import_on_definition) << 0;
- return nullptr;
- }
- return ::new (Context) WebAssemblyImportModuleAttr(Context, AL,
- AL.getImportModule());
-}
-
-WebAssemblyImportNameAttr *
-Sema::mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL) {
- auto *FD = cast<FunctionDecl>(D);
-
- if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportNameAttr>()) {
- if (ExistingAttr->getImportName() == AL.getImportName())
- return nullptr;
- Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) << 1
- << ExistingAttr->getImportName() << AL.getImportName();
- Diag(AL.getLoc(), diag::note_previous_attribute);
- return nullptr;
- }
- if (FD->hasBody()) {
- Diag(AL.getLoc(), diag::warn_import_on_definition) << 1;
- return nullptr;
- }
- return ::new (Context) WebAssemblyImportNameAttr(Context, AL,
- AL.getImportName());
-}
-
-static void
-handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- auto *FD = cast<FunctionDecl>(D);
-
- StringRef Str;
- SourceLocation ArgLoc;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
- return;
- if (FD->hasBody()) {
- S.Diag(AL.getLoc(), diag::warn_import_on_definition) << 0;
- return;
- }
-
- FD->addAttr(::new (S.Context)
- WebAssemblyImportModuleAttr(S.Context, AL, Str));
-}
-
-static void
-handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- auto *FD = cast<FunctionDecl>(D);
-
- StringRef Str;
- SourceLocation ArgLoc;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
- return;
- if (FD->hasBody()) {
- S.Diag(AL.getLoc(), diag::warn_import_on_definition) << 1;
- return;
- }
-
- FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(S.Context, AL, Str));
-}
-
-static void handleRISCVInterruptAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- // Warn about repeated attributes.
- if (const auto *A = D->getAttr<RISCVInterruptAttr>()) {
- S.Diag(AL.getRange().getBegin(),
- diag::warn_riscv_repeated_interrupt_attribute);
- S.Diag(A->getLocation(), diag::note_riscv_repeated_interrupt_attribute);
- return;
- }
-
- // Check the attribute argument. Argument is optional.
- if (!AL.checkAtMostNumArgs(S, 1))
- return;
-
- StringRef Str;
- SourceLocation ArgLoc;
-
- // 'machine'is the default interrupt mode.
- if (AL.getNumArgs() == 0)
- Str = "machine";
- else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
- return;
-
- // Semantic checks for a function with the 'interrupt' attribute:
- // - Must be a function.
- // - Must have no parameters.
- // - Must have the 'void' return type.
- // - The attribute itself must either have no argument or one of the
- // valid interrupt types, see [RISCVInterruptDocs].
-
- if (D->getFunctionType() == nullptr) {
- S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
- << AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
- return;
- }
-
- if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
- S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
- << /*RISC-V*/ 2 << 0;
- return;
- }
-
- if (!getFunctionOrMethodResultType(D)->isVoidType()) {
- S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
- << /*RISC-V*/ 2 << 1;
- return;
- }
-
- RISCVInterruptAttr::InterruptType Kind;
- if (!RISCVInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << Str
- << ArgLoc;
- return;
- }
-
- D->addAttr(::new (S.Context) RISCVInterruptAttr(S.Context, AL, Kind));
-}
-
static void handleInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Dispatch the interrupt attribute based on the current target.
switch (S.Context.getTargetInfo().getTriple().getArch()) {
case llvm::Triple::msp430:
- handleMSP430InterruptAttr(S, D, AL);
+ S.MSP430().handleInterruptAttr(D, AL);
break;
case llvm::Triple::mipsel:
case llvm::Triple::mips:
- handleMipsInterruptAttr(S, D, AL);
+ S.MIPS().handleInterruptAttr(D, AL);
break;
case llvm::Triple::m68k:
- handleM68kInterruptAttr(S, D, AL);
+ S.M68k().handleInterruptAttr(D, AL);
break;
case llvm::Triple::x86:
case llvm::Triple::x86_64:
- handleAnyX86InterruptAttr(S, D, AL);
+ S.X86().handleAnyInterruptAttr(D, AL);
break;
case llvm::Triple::avr:
- handleAVRInterruptAttr(S, D, AL);
+ S.AVR().handleInterruptAttr(D, AL);
break;
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
- handleRISCVInterruptAttr(S, D, AL);
+ S.RISCV().handleInterruptAttr(D, AL);
break;
default:
- handleARMInterruptAttr(S, D, AL);
+ S.ARM().handleInterruptAttr(D, AL);
break;
}
}
-static bool
-checkAMDGPUFlatWorkGroupSizeArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr,
- const AMDGPUFlatWorkGroupSizeAttr &Attr) {
- // Accept template arguments for now as they depend on something else.
- // We'll get to check them when they eventually get instantiated.
- if (MinExpr->isValueDependent() || MaxExpr->isValueDependent())
- return false;
-
- uint32_t Min = 0;
- if (!checkUInt32Argument(S, Attr, MinExpr, Min, 0))
- return true;
-
- uint32_t Max = 0;
- if (!checkUInt32Argument(S, Attr, MaxExpr, Max, 1))
- return true;
-
- if (Min == 0 && Max != 0) {
- S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
- << &Attr << 0;
- return true;
- }
- if (Min > Max) {
- S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
- << &Attr << 1;
- return true;
- }
-
- return false;
-}
-
-AMDGPUFlatWorkGroupSizeAttr *
-Sema::CreateAMDGPUFlatWorkGroupSizeAttr(const AttributeCommonInfo &CI,
- Expr *MinExpr, Expr *MaxExpr) {
- AMDGPUFlatWorkGroupSizeAttr TmpAttr(Context, CI, MinExpr, MaxExpr);
-
- if (checkAMDGPUFlatWorkGroupSizeArguments(*this, MinExpr, MaxExpr, TmpAttr))
- return nullptr;
- return ::new (Context)
- AMDGPUFlatWorkGroupSizeAttr(Context, CI, MinExpr, MaxExpr);
-}
-
-void Sema::addAMDGPUFlatWorkGroupSizeAttr(Decl *D,
- const AttributeCommonInfo &CI,
- Expr *MinExpr, Expr *MaxExpr) {
- if (auto *Attr = CreateAMDGPUFlatWorkGroupSizeAttr(CI, MinExpr, MaxExpr))
- D->addAttr(Attr);
-}
-
-static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- Expr *MinExpr = AL.getArgAsExpr(0);
- Expr *MaxExpr = AL.getArgAsExpr(1);
-
- S.addAMDGPUFlatWorkGroupSizeAttr(D, AL, MinExpr, MaxExpr);
-}
-
-static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr,
- Expr *MaxExpr,
- const AMDGPUWavesPerEUAttr &Attr) {
- if (S.DiagnoseUnexpandedParameterPack(MinExpr) ||
- (MaxExpr && S.DiagnoseUnexpandedParameterPack(MaxExpr)))
- return true;
-
- // Accept template arguments for now as they depend on something else.
- // We'll get to check them when they eventually get instantiated.
- if (MinExpr->isValueDependent() || (MaxExpr && MaxExpr->isValueDependent()))
- return false;
-
- uint32_t Min = 0;
- if (!checkUInt32Argument(S, Attr, MinExpr, Min, 0))
- return true;
-
- uint32_t Max = 0;
- if (MaxExpr && !checkUInt32Argument(S, Attr, MaxExpr, Max, 1))
- return true;
-
- if (Min == 0 && Max != 0) {
- S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
- << &Attr << 0;
- return true;
- }
- if (Max != 0 && Min > Max) {
- S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
- << &Attr << 1;
- return true;
- }
-
- return false;
-}
-
-AMDGPUWavesPerEUAttr *
-Sema::CreateAMDGPUWavesPerEUAttr(const AttributeCommonInfo &CI, Expr *MinExpr,
- Expr *MaxExpr) {
- AMDGPUWavesPerEUAttr TmpAttr(Context, CI, MinExpr, MaxExpr);
-
- if (checkAMDGPUWavesPerEUArguments(*this, MinExpr, MaxExpr, TmpAttr))
- return nullptr;
-
- return ::new (Context) AMDGPUWavesPerEUAttr(Context, CI, MinExpr, MaxExpr);
-}
-
-void Sema::addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI,
- Expr *MinExpr, Expr *MaxExpr) {
- if (auto *Attr = CreateAMDGPUWavesPerEUAttr(CI, MinExpr, MaxExpr))
- D->addAttr(Attr);
-}
-
-static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 2))
- return;
-
- Expr *MinExpr = AL.getArgAsExpr(0);
- Expr *MaxExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr;
-
- S.addAMDGPUWavesPerEUAttr(D, AL, MinExpr, MaxExpr);
-}
-
-static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- uint32_t NumSGPR = 0;
- Expr *NumSGPRExpr = AL.getArgAsExpr(0);
- if (!checkUInt32Argument(S, AL, NumSGPRExpr, NumSGPR))
- return;
-
- D->addAttr(::new (S.Context) AMDGPUNumSGPRAttr(S.Context, AL, NumSGPR));
-}
-
-static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- uint32_t NumVGPR = 0;
- Expr *NumVGPRExpr = AL.getArgAsExpr(0);
- if (!checkUInt32Argument(S, AL, NumVGPRExpr, NumVGPR))
- return;
-
- D->addAttr(::new (S.Context) AMDGPUNumVGPRAttr(S.Context, AL, NumVGPR));
-}
-
-static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- // If we try to apply it to a function pointer, don't warn, but don't
- // do anything, either. It doesn't matter anyway, because there's nothing
- // special about calling a force_align_arg_pointer function.
- const auto *VD = dyn_cast<ValueDecl>(D);
- if (VD && VD->getType()->isFunctionPointerType())
- return;
- // Also don't warn on function pointer typedefs.
- const auto *TD = dyn_cast<TypedefNameDecl>(D);
- if (TD && (TD->getUnderlyingType()->isFunctionPointerType() ||
- TD->getUnderlyingType()->isFunctionType()))
- return;
- // Attribute can only be applied to function types.
- if (!isa<FunctionDecl>(D)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
- << AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
- return;
- }
-
- D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(S.Context, AL));
-}
-
static void handleLayoutVersion(Sema &S, Decl *D, const ParsedAttr &AL) {
uint32_t Version;
Expr *VersionExpr = static_cast<Expr *>(AL.getArgAsExpr(0));
- if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Version))
+ if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), Version))
return;
// TODO: Investigate what happens with the next major version of MSVC.
@@ -8392,62 +5831,6 @@ static void handleInternalLinkageAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(Internal);
}
-static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (S.LangOpts.getOpenCLCompatibleVersion() < 200)
- S.Diag(AL.getLoc(), diag::err_attribute_requires_opencl_version)
- << AL << "2.0" << 1;
- else
- S.Diag(AL.getLoc(), diag::warn_opencl_attr_deprecated_ignored)
- << AL << S.LangOpts.getOpenCLVersionString();
-}
-
-static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (D->isInvalidDecl())
- return;
-
- // Check if there is only one access qualifier.
- if (D->hasAttr<OpenCLAccessAttr>()) {
- if (D->getAttr<OpenCLAccessAttr>()->getSemanticSpelling() ==
- AL.getSemanticSpelling()) {
- S.Diag(AL.getLoc(), diag::warn_duplicate_declspec)
- << AL.getAttrName()->getName() << AL.getRange();
- } else {
- S.Diag(AL.getLoc(), diag::err_opencl_multiple_access_qualifiers)
- << D->getSourceRange();
- D->setInvalidDecl(true);
- return;
- }
- }
-
- // OpenCL v2.0 s6.6 - read_write can be used for image types to specify that
- // an image object can be read and written. OpenCL v2.0 s6.13.6 - A kernel
- // cannot read from and write to the same pipe object. Using the read_write
- // (or __read_write) qualifier with the pipe qualifier is a compilation error.
- // OpenCL v3.0 s6.8 - For OpenCL C 2.0, or with the
- // __opencl_c_read_write_images feature, image objects specified as arguments
- // to a kernel can additionally be declared to be read-write.
- // C++ for OpenCL 1.0 inherits rule from OpenCL C v2.0.
- // C++ for OpenCL 2021 inherits rule from OpenCL C v3.0.
- if (const auto *PDecl = dyn_cast<ParmVarDecl>(D)) {
- const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr();
- if (AL.getAttrName()->getName().contains("read_write")) {
- bool ReadWriteImagesUnsupported =
- (S.getLangOpts().getOpenCLCompatibleVersion() < 200) ||
- (S.getLangOpts().getOpenCLCompatibleVersion() == 300 &&
- !S.getOpenCLOptions().isSupported("__opencl_c_read_write_images",
- S.getLangOpts()));
- if (ReadWriteImagesUnsupported || DeclTy->isPipeType()) {
- S.Diag(AL.getLoc(), diag::err_opencl_invalid_read_write)
- << AL << PDecl->getType() << DeclTy->isImageType();
- D->setInvalidDecl(true);
- return;
- }
- }
- }
-
- D->addAttr(::new (S.Context) OpenCLAccessAttr(S.Context, AL));
-}
-
static void handleZeroCallUsedRegsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Check that the argument is a string literal.
StringRef KindStr;
@@ -8466,133 +5849,44 @@ static void handleZeroCallUsedRegsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(ZeroCallUsedRegsAttr::Create(S.Context, Kind, AL));
}
-static void handleCountedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!AL.isArgIdent(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIdentifier;
- return;
- }
-
- IdentifierLoc *IL = AL.getArgAsIdent(0);
- CountedByAttr *CBA =
- ::new (S.Context) CountedByAttr(S.Context, AL, IL->Ident);
- CBA->setCountedByFieldLoc(IL->Loc);
- D->addAttr(CBA);
-}
-
-static const FieldDecl *
-FindFieldInTopLevelOrAnonymousStruct(const RecordDecl *RD,
- const IdentifierInfo *FieldName) {
- for (const Decl *D : RD->decls()) {
- if (const auto *FD = dyn_cast<FieldDecl>(D))
- if (FD->getName() == FieldName->getName())
- return FD;
-
- if (const auto *R = dyn_cast<RecordDecl>(D))
- if (const FieldDecl *FD =
- FindFieldInTopLevelOrAnonymousStruct(R, FieldName))
- return FD;
- }
-
- return nullptr;
-}
-
-bool Sema::CheckCountedByAttr(Scope *S, const FieldDecl *FD) {
- LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
- LangOptions::StrictFlexArraysLevelKind::IncompleteOnly;
- if (!Decl::isFlexibleArrayMemberLike(Context, FD, FD->getType(),
- StrictFlexArraysLevel, true)) {
- // The "counted_by" attribute must be on a flexible array member.
- SourceRange SR = FD->getLocation();
- Diag(SR.getBegin(), diag::err_counted_by_attr_not_on_flexible_array_member)
- << SR;
- return true;
- }
-
- const auto *CBA = FD->getAttr<CountedByAttr>();
- const IdentifierInfo *FieldName = CBA->getCountedByField();
-
- auto GetNonAnonStructOrUnion = [](const RecordDecl *RD) {
- while (RD && !RD->getDeclName())
- if (const auto *R = dyn_cast<RecordDecl>(RD->getDeclContext()))
- RD = R;
- else
- break;
-
- return RD;
- };
-
- const RecordDecl *EnclosingRD = GetNonAnonStructOrUnion(FD->getParent());
- const FieldDecl *CountFD =
- FindFieldInTopLevelOrAnonymousStruct(EnclosingRD, FieldName);
-
- if (!CountFD) {
- DeclarationNameInfo NameInfo(FieldName,
- CBA->getCountedByFieldLoc().getBegin());
- LookupResult MemResult(*this, NameInfo, Sema::LookupMemberName);
- LookupName(MemResult, S);
-
- if (!MemResult.empty()) {
- SourceRange SR = CBA->getCountedByFieldLoc();
- Diag(SR.getBegin(), diag::err_flexible_array_count_not_in_same_struct)
- << CBA->getCountedByField() << SR;
-
- if (auto *ND = MemResult.getAsSingle<NamedDecl>()) {
- SR = ND->getLocation();
- Diag(SR.getBegin(), diag::note_flexible_array_counted_by_attr_field)
- << ND << SR;
- }
+static void handleCountedByAttrField(Sema &S, Decl *D, const ParsedAttr &AL) {
+ auto *FD = dyn_cast<FieldDecl>(D);
+ assert(FD);
- return true;
- } else {
- // The "counted_by" field needs to exist in the struct.
- LookupResult OrdResult(*this, NameInfo, Sema::LookupOrdinaryName);
- LookupName(OrdResult, S);
-
- if (!OrdResult.empty()) {
- SourceRange SR = FD->getLocation();
- Diag(SR.getBegin(), diag::err_counted_by_must_be_in_structure)
- << FieldName << SR;
-
- if (auto *ND = OrdResult.getAsSingle<NamedDecl>()) {
- SR = ND->getLocation();
- Diag(SR.getBegin(), diag::note_flexible_array_counted_by_attr_field)
- << ND << SR;
- }
-
- return true;
- }
- }
-
- CXXScopeSpec SS;
- DeclFilterCCC<FieldDecl> Filter(FieldName);
- return DiagnoseEmptyLookup(S, SS, MemResult, Filter, nullptr, std::nullopt,
- const_cast<DeclContext *>(FD->getDeclContext()));
- }
+ auto *CountExpr = AL.getArgAsExpr(0);
+ if (!CountExpr)
+ return;
- if (CountFD->hasAttr<CountedByAttr>()) {
- // The "counted_by" field can't point to the flexible array member.
- SourceRange SR = CBA->getCountedByFieldLoc();
- Diag(SR.getBegin(), diag::err_counted_by_attr_refers_to_flexible_array)
- << CBA->getCountedByField() << SR;
- return true;
+ bool CountInBytes;
+ bool OrNull;
+ switch (AL.getKind()) {
+ case ParsedAttr::AT_CountedBy:
+ CountInBytes = false;
+ OrNull = false;
+ break;
+ case ParsedAttr::AT_CountedByOrNull:
+ CountInBytes = false;
+ OrNull = true;
+ break;
+ case ParsedAttr::AT_SizedBy:
+ CountInBytes = true;
+ OrNull = false;
+ break;
+ case ParsedAttr::AT_SizedByOrNull:
+ CountInBytes = true;
+ OrNull = true;
+ break;
+ default:
+ llvm_unreachable("unexpected counted_by family attribute");
}
- if (!CountFD->getType()->isIntegerType() ||
- CountFD->getType()->isBooleanType()) {
- // The "counted_by" field must have an integer type.
- SourceRange SR = CBA->getCountedByFieldLoc();
- Diag(SR.getBegin(),
- diag::err_flexible_array_counted_by_attr_field_not_integer)
- << CBA->getCountedByField() << SR;
-
- SR = CountFD->getLocation();
- Diag(SR.getBegin(), diag::note_flexible_array_counted_by_attr_field)
- << CountFD << SR;
- return true;
- }
+ llvm::SmallVector<TypeCoupledDeclRefInfo, 1> Decls;
+ if (S.CheckCountedByAttrOnField(FD, CountExpr, Decls, CountInBytes, OrNull))
+ return;
- return false;
+ QualType CAT = S.BuildCountAttributedArrayOrPointerType(
+ FD->getType(), CountExpr, CountInBytes, OrNull);
+ FD->setType(CAT);
}
static void handleFunctionReturnThunksAttr(Sema &S, Decl *D,
@@ -8635,45 +5929,6 @@ static void handleNoUniqueAddressAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(NoUniqueAddressAttr::Create(S.Context, AL));
}
-static void handleSYCLKernelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // The 'sycl_kernel' attribute applies only to function templates.
- const auto *FD = cast<FunctionDecl>(D);
- const FunctionTemplateDecl *FT = FD->getDescribedFunctionTemplate();
- assert(FT && "Function template is expected");
-
- // Function template must have at least two template parameters.
- const TemplateParameterList *TL = FT->getTemplateParameters();
- if (TL->size() < 2) {
- S.Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_template_params);
- return;
- }
-
- // Template parameters must be typenames.
- for (unsigned I = 0; I < 2; ++I) {
- const NamedDecl *TParam = TL->getParam(I);
- if (isa<NonTypeTemplateParmDecl>(TParam)) {
- S.Diag(FT->getLocation(),
- diag::warn_sycl_kernel_invalid_template_param_type);
- return;
- }
- }
-
- // Function must have at least one argument.
- if (getFunctionOrMethodNumParams(D) != 1) {
- S.Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_function_params);
- return;
- }
-
- // Function must return void.
- QualType RetTy = getFunctionOrMethodResultType(D);
- if (!RetTy->isVoidType()) {
- S.Diag(FT->getLocation(), diag::warn_sycl_kernel_return_type);
- return;
- }
-
- handleSimpleAttribute<SYCLKernelAttr>(S, D, AL);
-}
-
static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) {
if (!cast<VarDecl>(D)->hasGlobalStorage()) {
S.Diag(D->getLocation(), diag::err_destroy_attr_on_non_static_var)
@@ -8693,81 +5948,6 @@ static void handleUninitializedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(::new (S.Context) UninitializedAttr(S.Context, AL));
}
-static bool tryMakeVariablePseudoStrong(Sema &S, VarDecl *VD,
- bool DiagnoseFailure) {
- QualType Ty = VD->getType();
- if (!Ty->isObjCRetainableType()) {
- if (DiagnoseFailure) {
- S.Diag(VD->getBeginLoc(), diag::warn_ignored_objc_externally_retained)
- << 0;
- }
- return false;
- }
-
- Qualifiers::ObjCLifetime LifetimeQual = Ty.getQualifiers().getObjCLifetime();
-
- // Sema::inferObjCARCLifetime must run after processing decl attributes
- // (because __block lowers to an attribute), so if the lifetime hasn't been
- // explicitly specified, infer it locally now.
- if (LifetimeQual == Qualifiers::OCL_None)
- LifetimeQual = Ty->getObjCARCImplicitLifetime();
-
- // The attributes only really makes sense for __strong variables; ignore any
- // attempts to annotate a parameter with any other lifetime qualifier.
- if (LifetimeQual != Qualifiers::OCL_Strong) {
- if (DiagnoseFailure) {
- S.Diag(VD->getBeginLoc(), diag::warn_ignored_objc_externally_retained)
- << 1;
- }
- return false;
- }
-
- // Tampering with the type of a VarDecl here is a bit of a hack, but we need
- // to ensure that the variable is 'const' so that we can error on
- // modification, which can otherwise over-release.
- VD->setType(Ty.withConst());
- VD->setARCPseudoStrong(true);
- return true;
-}
-
-static void handleObjCExternallyRetainedAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- if (auto *VD = dyn_cast<VarDecl>(D)) {
- assert(!isa<ParmVarDecl>(VD) && "should be diagnosed automatically");
- if (!VD->hasLocalStorage()) {
- S.Diag(D->getBeginLoc(), diag::warn_ignored_objc_externally_retained)
- << 0;
- return;
- }
-
- if (!tryMakeVariablePseudoStrong(S, VD, /*DiagnoseFailure=*/true))
- return;
-
- handleSimpleAttribute<ObjCExternallyRetainedAttr>(S, D, AL);
- return;
- }
-
- // If D is a function-like declaration (method, block, or function), then we
- // make every parameter psuedo-strong.
- unsigned NumParams =
- hasFunctionProto(D) ? getFunctionOrMethodNumParams(D) : 0;
- for (unsigned I = 0; I != NumParams; ++I) {
- auto *PVD = const_cast<ParmVarDecl *>(getFunctionOrMethodParam(D, I));
- QualType Ty = PVD->getType();
-
- // If a user wrote a parameter with __strong explicitly, then assume they
- // want "real" strong semantics for that parameter. This works because if
- // the parameter was written with __strong, then the strong qualifier will
- // be non-local.
- if (Ty.getLocalUnqualifiedType().getQualifiers().getObjCLifetime() ==
- Qualifiers::OCL_Strong)
- continue;
-
- tryMakeVariablePseudoStrong(S, PVD, /*DiagnoseFailure=*/false);
- }
- handleSimpleAttribute<ObjCExternallyRetainedAttr>(S, D, AL);
-}
-
static void handleMIGServerRoutineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Check that the return type is a `typedef int kern_return_t` or a typedef
// around it, because otherwise MIG convention checks make no sense.
@@ -8922,6 +6102,116 @@ EnforceTCBLeafAttr *Sema::mergeEnforceTCBLeafAttr(
*this, D, AL);
}
+static void handleVTablePointerAuthentication(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ CXXRecordDecl *Decl = cast<CXXRecordDecl>(D);
+ const uint32_t NumArgs = AL.getNumArgs();
+ if (NumArgs > 4) {
+ S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 4;
+ AL.setInvalid();
+ }
+
+ if (NumArgs == 0) {
+ S.Diag(AL.getLoc(), diag::err_attribute_too_few_arguments) << AL;
+ AL.setInvalid();
+ return;
+ }
+
+ if (D->getAttr<VTablePointerAuthenticationAttr>()) {
+ S.Diag(AL.getLoc(), diag::err_duplicated_vtable_pointer_auth) << Decl;
+ AL.setInvalid();
+ }
+
+ auto KeyType = VTablePointerAuthenticationAttr::VPtrAuthKeyType::DefaultKey;
+ if (AL.isArgIdent(0)) {
+ IdentifierLoc *IL = AL.getArgAsIdent(0);
+ if (!VTablePointerAuthenticationAttr::ConvertStrToVPtrAuthKeyType(
+ IL->Ident->getName(), KeyType)) {
+ S.Diag(IL->Loc, diag::err_invalid_authentication_key) << IL->Ident;
+ AL.setInvalid();
+ }
+ if (KeyType == VTablePointerAuthenticationAttr::DefaultKey &&
+ !S.getLangOpts().PointerAuthCalls) {
+ S.Diag(AL.getLoc(), diag::err_no_default_vtable_pointer_auth) << 0;
+ AL.setInvalid();
+ }
+ } else {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
+ << AL << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ auto AddressDiversityMode = VTablePointerAuthenticationAttr::
+ AddressDiscriminationMode::DefaultAddressDiscrimination;
+ if (AL.getNumArgs() > 1) {
+ if (AL.isArgIdent(1)) {
+ IdentifierLoc *IL = AL.getArgAsIdent(1);
+ if (!VTablePointerAuthenticationAttr::
+ ConvertStrToAddressDiscriminationMode(IL->Ident->getName(),
+ AddressDiversityMode)) {
+ S.Diag(IL->Loc, diag::err_invalid_address_discrimination) << IL->Ident;
+ AL.setInvalid();
+ }
+ if (AddressDiversityMode ==
+ VTablePointerAuthenticationAttr::DefaultAddressDiscrimination &&
+ !S.getLangOpts().PointerAuthCalls) {
+ S.Diag(IL->Loc, diag::err_no_default_vtable_pointer_auth) << 1;
+ AL.setInvalid();
+ }
+ } else {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
+ << AL << AANT_ArgumentIdentifier;
+ }
+ }
+
+ auto ED = VTablePointerAuthenticationAttr::ExtraDiscrimination::
+ DefaultExtraDiscrimination;
+ if (AL.getNumArgs() > 2) {
+ if (AL.isArgIdent(2)) {
+ IdentifierLoc *IL = AL.getArgAsIdent(2);
+ if (!VTablePointerAuthenticationAttr::ConvertStrToExtraDiscrimination(
+ IL->Ident->getName(), ED)) {
+ S.Diag(IL->Loc, diag::err_invalid_extra_discrimination) << IL->Ident;
+ AL.setInvalid();
+ }
+ if (ED == VTablePointerAuthenticationAttr::DefaultExtraDiscrimination &&
+ !S.getLangOpts().PointerAuthCalls) {
+ S.Diag(AL.getLoc(), diag::err_no_default_vtable_pointer_auth) << 2;
+ AL.setInvalid();
+ }
+ } else {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
+ << AL << AANT_ArgumentIdentifier;
+ }
+ }
+
+ uint32_t CustomDiscriminationValue = 0;
+ if (ED == VTablePointerAuthenticationAttr::CustomDiscrimination) {
+ if (NumArgs < 4) {
+ S.Diag(AL.getLoc(), diag::err_missing_custom_discrimination) << AL << 4;
+ AL.setInvalid();
+ return;
+ }
+ if (NumArgs > 4) {
+ S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 4;
+ AL.setInvalid();
+ }
+
+ if (!AL.isArgExpr(3) || !S.checkUInt32Argument(AL, AL.getArgAsExpr(3),
+ CustomDiscriminationValue)) {
+ S.Diag(AL.getLoc(), diag::err_invalid_custom_discrimination);
+ AL.setInvalid();
+ }
+ } else if (NumArgs > 3) {
+ S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 3;
+ AL.setInvalid();
+ }
+
+ Decl->addAttr(::new (S.Context) VTablePointerAuthenticationAttr(
+ S.Context, AL, KeyType, AddressDiversityMode, ED,
+ CustomDiscriminationValue));
+}
+
//===----------------------------------------------------------------------===//
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
@@ -8957,82 +6247,6 @@ static bool MustDelayAttributeArguments(const ParsedAttr &AL) {
return false;
}
-static bool checkArmNewAttrMutualExclusion(
- Sema &S, const ParsedAttr &AL, const FunctionProtoType *FPT,
- FunctionType::ArmStateValue CurrentState, StringRef StateName) {
- auto CheckForIncompatibleAttr =
- [&](FunctionType::ArmStateValue IncompatibleState,
- StringRef IncompatibleStateName) {
- if (CurrentState == IncompatibleState) {
- S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
- << (std::string("'__arm_new(\"") + StateName.str() + "\")'")
- << (std::string("'") + IncompatibleStateName.str() + "(\"" +
- StateName.str() + "\")'")
- << true;
- AL.setInvalid();
- }
- };
-
- CheckForIncompatibleAttr(FunctionType::ARM_In, "__arm_in");
- CheckForIncompatibleAttr(FunctionType::ARM_Out, "__arm_out");
- CheckForIncompatibleAttr(FunctionType::ARM_InOut, "__arm_inout");
- CheckForIncompatibleAttr(FunctionType::ARM_Preserves, "__arm_preserves");
- return AL.isInvalid();
-}
-
-static void handleArmNewAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!AL.getNumArgs()) {
- S.Diag(AL.getLoc(), diag::err_missing_arm_state) << AL;
- AL.setInvalid();
- return;
- }
-
- std::vector<StringRef> NewState;
- if (const auto *ExistingAttr = D->getAttr<ArmNewAttr>()) {
- for (StringRef S : ExistingAttr->newArgs())
- NewState.push_back(S);
- }
-
- bool HasZA = false;
- bool HasZT0 = false;
- for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
- StringRef StateName;
- SourceLocation LiteralLoc;
- if (!S.checkStringLiteralArgumentAttr(AL, I, StateName, &LiteralLoc))
- return;
-
- if (StateName == "za")
- HasZA = true;
- else if (StateName == "zt0")
- HasZT0 = true;
- else {
- S.Diag(LiteralLoc, diag::err_unknown_arm_state) << StateName;
- AL.setInvalid();
- return;
- }
-
- if (!llvm::is_contained(NewState, StateName)) // Avoid adding duplicates.
- NewState.push_back(StateName);
- }
-
- if (auto *FPT = dyn_cast<FunctionProtoType>(D->getFunctionType())) {
- FunctionType::ArmStateValue ZAState =
- FunctionType::getArmZAState(FPT->getAArch64SMEAttributes());
- if (HasZA && ZAState != FunctionType::ARM_None &&
- checkArmNewAttrMutualExclusion(S, AL, FPT, ZAState, "za"))
- return;
- FunctionType::ArmStateValue ZT0State =
- FunctionType::getArmZT0State(FPT->getAArch64SMEAttributes());
- if (HasZT0 && ZT0State != FunctionType::ARM_None &&
- checkArmNewAttrMutualExclusion(S, AL, FPT, ZT0State, "zt0"))
- return;
- }
-
- D->dropAttr<ArmNewAttr>();
- D->addAttr(::new (S.Context)
- ArmNewAttr(S.Context, AL, NewState.data(), NewState.size()));
-}
-
/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
/// the attribute applies to decls. If the attribute is a type attribute, just
/// silently ignore it if a GNU attribute.
@@ -9043,8 +6257,14 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
return;
// Ignore C++11 attributes on declarator chunks: they appertain to the type
- // instead.
- if (AL.isCXX11Attribute() && !Options.IncludeCXX11Attributes)
+ // instead. Note, isCXX11Attribute() will look at whether the attribute is
+ // [[]] or alignas, while isC23Attribute() will only look at [[]]. This is
+ // important for ensuring that alignas in C23 is properly handled on a
+ // structure member declaration because it is a type-specifier-qualifier in
+ // C but still applies to the declaration rather than the type.
+ if ((S.getLangOpts().CPlusPlus ? AL.isCXX11Attribute()
+ : AL.isC23Attribute()) &&
+ !Options.IncludeCXX11Attributes)
return;
// Unknown attributes are automatically warned on. Target-specific attributes
@@ -9155,7 +6375,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
handleInterruptAttr(S, D, AL);
break;
case ParsedAttr::AT_X86ForceAlignArgPointer:
- handleX86ForceAlignArgPointerAttr(S, D, AL);
+ S.X86().handleForceAlignArgPointerAttr(D, AL);
break;
case ParsedAttr::AT_ReadOnlyPlacement:
handleSimpleAttribute<ReadOnlyPlacementAttr>(S, D, AL);
@@ -9165,22 +6385,25 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
handleDLLAttr(S, D, AL);
break;
case ParsedAttr::AT_AMDGPUFlatWorkGroupSize:
- handleAMDGPUFlatWorkGroupSizeAttr(S, D, AL);
+ S.AMDGPU().handleAMDGPUFlatWorkGroupSizeAttr(D, AL);
break;
case ParsedAttr::AT_AMDGPUWavesPerEU:
- handleAMDGPUWavesPerEUAttr(S, D, AL);
+ S.AMDGPU().handleAMDGPUWavesPerEUAttr(D, AL);
break;
case ParsedAttr::AT_AMDGPUNumSGPR:
- handleAMDGPUNumSGPRAttr(S, D, AL);
+ S.AMDGPU().handleAMDGPUNumSGPRAttr(D, AL);
break;
case ParsedAttr::AT_AMDGPUNumVGPR:
- handleAMDGPUNumVGPRAttr(S, D, AL);
+ S.AMDGPU().handleAMDGPUNumVGPRAttr(D, AL);
+ break;
+ case ParsedAttr::AT_AMDGPUMaxNumWorkGroups:
+ S.AMDGPU().handleAMDGPUMaxNumWorkGroupsAttr(D, AL);
break;
case ParsedAttr::AT_AVRSignal:
- handleAVRSignalAttr(S, D, AL);
+ S.AVR().handleSignalAttr(D, AL);
break;
case ParsedAttr::AT_BPFPreserveAccessIndex:
- handleBPFPreserveAccessIndexAttr(S, D, AL);
+ S.BPF().handlePreserveAccessIndexAttr(D, AL);
break;
case ParsedAttr::AT_BPFPreserveStaticOffset:
handleSimpleAttribute<BPFPreserveStaticOffsetAttr>(S, D, AL);
@@ -9189,19 +6412,19 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
handleBTFDeclTagAttr(S, D, AL);
break;
case ParsedAttr::AT_WebAssemblyExportName:
- handleWebAssemblyExportNameAttr(S, D, AL);
+ S.Wasm().handleWebAssemblyExportNameAttr(D, AL);
break;
case ParsedAttr::AT_WebAssemblyImportModule:
- handleWebAssemblyImportModuleAttr(S, D, AL);
+ S.Wasm().handleWebAssemblyImportModuleAttr(D, AL);
break;
case ParsedAttr::AT_WebAssemblyImportName:
- handleWebAssemblyImportNameAttr(S, D, AL);
+ S.Wasm().handleWebAssemblyImportNameAttr(D, AL);
break;
case ParsedAttr::AT_IBOutlet:
- handleIBOutlet(S, D, AL);
+ S.ObjC().handleIBOutlet(D, AL);
break;
case ParsedAttr::AT_IBOutletCollection:
- handleIBOutletCollection(S, D, AL);
+ S.ObjC().handleIBOutletCollection(D, AL);
break;
case ParsedAttr::AT_IFunc:
handleIFuncAttr(S, D, AL);
@@ -9264,6 +6487,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_Error:
handleErrorAttr(S, D, AL);
break;
+ case ParsedAttr::AT_ExcludeFromExplicitInstantiation:
+ handleExcludeFromExplicitInstantiationAttr(S, D, AL);
+ break;
case ParsedAttr::AT_DiagnoseIf:
handleDiagnoseIfAttr(S, D, AL);
break;
@@ -9289,7 +6515,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
handleEnumExtensibilityAttr(S, D, AL);
break;
case ParsedAttr::AT_SYCLKernel:
- handleSYCLKernelAttr(S, D, AL);
+ S.SYCL().handleKernelAttr(D, AL);
break;
case ParsedAttr::AT_SYCLSpecialClass:
handleSimpleAttribute<SYCLSpecialClassAttr>(S, D, AL);
@@ -9375,53 +6601,54 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
handleVecReturnAttr(S, D, AL);
break;
case ParsedAttr::AT_ObjCOwnership:
- handleObjCOwnershipAttr(S, D, AL);
+ S.ObjC().handleOwnershipAttr(D, AL);
break;
case ParsedAttr::AT_ObjCPreciseLifetime:
- handleObjCPreciseLifetimeAttr(S, D, AL);
+ S.ObjC().handlePreciseLifetimeAttr(D, AL);
break;
case ParsedAttr::AT_ObjCReturnsInnerPointer:
- handleObjCReturnsInnerPointerAttr(S, D, AL);
+ S.ObjC().handleReturnsInnerPointerAttr(D, AL);
break;
case ParsedAttr::AT_ObjCRequiresSuper:
- handleObjCRequiresSuperAttr(S, D, AL);
+ S.ObjC().handleRequiresSuperAttr(D, AL);
break;
case ParsedAttr::AT_ObjCBridge:
- handleObjCBridgeAttr(S, D, AL);
+ S.ObjC().handleBridgeAttr(D, AL);
break;
case ParsedAttr::AT_ObjCBridgeMutable:
- handleObjCBridgeMutableAttr(S, D, AL);
+ S.ObjC().handleBridgeMutableAttr(D, AL);
break;
case ParsedAttr::AT_ObjCBridgeRelated:
- handleObjCBridgeRelatedAttr(S, D, AL);
+ S.ObjC().handleBridgeRelatedAttr(D, AL);
break;
case ParsedAttr::AT_ObjCDesignatedInitializer:
- handleObjCDesignatedInitializer(S, D, AL);
+ S.ObjC().handleDesignatedInitializer(D, AL);
break;
case ParsedAttr::AT_ObjCRuntimeName:
- handleObjCRuntimeName(S, D, AL);
+ S.ObjC().handleRuntimeName(D, AL);
break;
case ParsedAttr::AT_ObjCBoxable:
- handleObjCBoxable(S, D, AL);
+ S.ObjC().handleBoxable(D, AL);
break;
case ParsedAttr::AT_NSErrorDomain:
- handleNSErrorDomain(S, D, AL);
+ S.ObjC().handleNSErrorDomain(D, AL);
break;
case ParsedAttr::AT_CFConsumed:
case ParsedAttr::AT_NSConsumed:
case ParsedAttr::AT_OSConsumed:
- S.AddXConsumedAttr(D, AL, parsedAttrToRetainOwnershipKind(AL),
- /*IsTemplateInstantiation=*/false);
+ S.ObjC().AddXConsumedAttr(D, AL,
+ S.ObjC().parsedAttrToRetainOwnershipKind(AL),
+ /*IsTemplateInstantiation=*/false);
break;
case ParsedAttr::AT_OSReturnsRetainedOnZero:
handleSimpleAttributeOrDiagnose<OSReturnsRetainedOnZeroAttr>(
- S, D, AL, isValidOSObjectOutParameter(D),
+ S, D, AL, S.ObjC().isValidOSObjectOutParameter(D),
diag::warn_ns_attribute_wrong_parameter_type,
/*Extra Args=*/AL, /*pointer-to-OSObject-pointer*/ 3, AL.getRange());
break;
case ParsedAttr::AT_OSReturnsRetainedOnNonZero:
handleSimpleAttributeOrDiagnose<OSReturnsRetainedOnNonZeroAttr>(
- S, D, AL, isValidOSObjectOutParameter(D),
+ S, D, AL, S.ObjC().isValidOSObjectOutParameter(D),
diag::warn_ns_attribute_wrong_parameter_type,
/*Extra Args=*/AL, /*pointer-to-OSObject-poointer*/ 3, AL.getRange());
break;
@@ -9432,7 +6659,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_CFReturnsRetained:
case ParsedAttr::AT_OSReturnsNotRetained:
case ParsedAttr::AT_OSReturnsRetained:
- handleXReturnsXRetainedAttr(S, D, AL);
+ S.ObjC().handleXReturnsXRetainedAttr(D, AL);
break;
case ParsedAttr::AT_WorkGroupSizeHint:
handleWorkGroupSize<WorkGroupSizeHintAttr>(S, D, AL);
@@ -9441,7 +6668,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
handleWorkGroupSize<ReqdWorkGroupSizeAttr>(S, D, AL);
break;
case ParsedAttr::AT_OpenCLIntelReqdSubGroupSize:
- handleSubGroupSize(S, D, AL);
+ S.OpenCL().handleSubGroupSize(D, AL);
break;
case ParsedAttr::AT_VecTypeHint:
handleVecTypeHint(S, D, AL);
@@ -9485,18 +6712,18 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_Unavailable:
handleAttrWithMessage<UnavailableAttr>(S, D, AL);
break;
- case ParsedAttr::AT_Assumption:
- handleAssumumptionAttr(S, D, AL);
+ case ParsedAttr::AT_OMPAssume:
+ S.OpenMP().handleOMPAssumeAttr(D, AL);
break;
case ParsedAttr::AT_ObjCDirect:
- handleObjCDirectAttr(S, D, AL);
+ S.ObjC().handleDirectAttr(D, AL);
break;
case ParsedAttr::AT_ObjCDirectMembers:
- handleObjCDirectMembersAttr(S, D, AL);
+ S.ObjC().handleDirectMembersAttr(D, AL);
handleSimpleAttribute<ObjCDirectMembersAttr>(S, D, AL);
break;
case ParsedAttr::AT_ObjCExplicitProtocolImpl:
- handleObjCSuppresProtocolAttr(S, D, AL);
+ S.ObjC().handleSuppresProtocolAttr(D, AL);
break;
case ParsedAttr::AT_Unused:
handleUnusedAttr(S, D, AL);
@@ -9520,16 +6747,16 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
handleTransparentUnionAttr(S, D, AL);
break;
case ParsedAttr::AT_ObjCMethodFamily:
- handleObjCMethodFamilyAttr(S, D, AL);
+ S.ObjC().handleMethodFamilyAttr(D, AL);
break;
case ParsedAttr::AT_ObjCNSObject:
- handleObjCNSObject(S, D, AL);
+ S.ObjC().handleNSObject(D, AL);
break;
case ParsedAttr::AT_ObjCIndependentClass:
- handleObjCIndependentClass(S, D, AL);
+ S.ObjC().handleIndependentClass(D, AL);
break;
case ParsedAttr::AT_Blocks:
- handleBlocksAttr(S, D, AL);
+ S.ObjC().handleBlocksAttr(D, AL);
break;
case ParsedAttr::AT_Sentinel:
handleSentinelAttr(S, D, AL);
@@ -9541,7 +6768,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
handleNoDebugAttr(S, D, AL);
break;
case ParsedAttr::AT_CmseNSEntry:
- handleCmseNSEntryAttr(S, D, AL);
+ S.ARM().handleCmseNSEntryAttr(D, AL);
break;
case ParsedAttr::AT_StdCall:
case ParsedAttr::AT_CDecl:
@@ -9562,6 +6789,8 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_AArch64SVEPcs:
case ParsedAttr::AT_AMDGPUKernelCall:
case ParsedAttr::AT_M68kRTD:
+ case ParsedAttr::AT_PreserveNone:
+ case ParsedAttr::AT_RISCVVectorCC:
handleCallConvAttr(S, D, AL);
break;
case ParsedAttr::AT_Suppress:
@@ -9572,22 +6801,22 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
handleLifetimeCategoryAttr(S, D, AL);
break;
case ParsedAttr::AT_OpenCLAccess:
- handleOpenCLAccessAttr(S, D, AL);
+ S.OpenCL().handleAccessAttr(D, AL);
break;
case ParsedAttr::AT_OpenCLNoSVM:
- handleOpenCLNoSVMAttr(S, D, AL);
+ S.OpenCL().handleNoSVMAttr(D, AL);
break;
case ParsedAttr::AT_SwiftContext:
- S.AddParameterABIAttr(D, AL, ParameterABI::SwiftContext);
+ S.Swift().AddParameterABIAttr(D, AL, ParameterABI::SwiftContext);
break;
case ParsedAttr::AT_SwiftAsyncContext:
- S.AddParameterABIAttr(D, AL, ParameterABI::SwiftAsyncContext);
+ S.Swift().AddParameterABIAttr(D, AL, ParameterABI::SwiftAsyncContext);
break;
case ParsedAttr::AT_SwiftErrorResult:
- S.AddParameterABIAttr(D, AL, ParameterABI::SwiftErrorResult);
+ S.Swift().AddParameterABIAttr(D, AL, ParameterABI::SwiftErrorResult);
break;
case ParsedAttr::AT_SwiftIndirectResult:
- S.AddParameterABIAttr(D, AL, ParameterABI::SwiftIndirectResult);
+ S.Swift().AddParameterABIAttr(D, AL, ParameterABI::SwiftIndirectResult);
break;
case ParsedAttr::AT_InternalLinkage:
handleInternalLinkageAttr(S, D, AL);
@@ -9610,7 +6839,10 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
break;
case ParsedAttr::AT_CountedBy:
- handleCountedByAttr(S, D, AL);
+ case ParsedAttr::AT_CountedByOrNull:
+ case ParsedAttr::AT_SizedBy:
+ case ParsedAttr::AT_SizedByOrNull:
+ handleCountedByAttrField(S, D, AL);
break;
// Microsoft attributes:
@@ -9629,25 +6861,34 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_MSConstexpr:
handleMSConstexprAttr(S, D, AL);
break;
+ case ParsedAttr::AT_HybridPatchable:
+ handleSimpleAttribute<HybridPatchableAttr>(S, D, AL);
+ break;
// HLSL attributes:
case ParsedAttr::AT_HLSLNumThreads:
- handleHLSLNumThreadsAttr(S, D, AL);
+ S.HLSL().handleNumThreadsAttr(D, AL);
break;
case ParsedAttr::AT_HLSLSV_GroupIndex:
handleSimpleAttribute<HLSLSV_GroupIndexAttr>(S, D, AL);
break;
case ParsedAttr::AT_HLSLSV_DispatchThreadID:
- handleHLSLSV_DispatchThreadIDAttr(S, D, AL);
+ S.HLSL().handleSV_DispatchThreadIDAttr(D, AL);
+ break;
+ case ParsedAttr::AT_HLSLPackOffset:
+ S.HLSL().handlePackOffsetAttr(D, AL);
break;
case ParsedAttr::AT_HLSLShader:
- handleHLSLShaderAttr(S, D, AL);
+ S.HLSL().handleShaderAttr(D, AL);
break;
case ParsedAttr::AT_HLSLResourceBinding:
- handleHLSLResourceBindingAttr(S, D, AL);
+ S.HLSL().handleResourceBindingAttr(D, AL);
+ break;
+ case ParsedAttr::AT_HLSLResourceClass:
+ S.HLSL().handleResourceClassAttr(D, AL);
break;
case ParsedAttr::AT_HLSLParamModifier:
- handleHLSLParamModifierAttr(S, D, AL);
+ S.HLSL().handleParamModifierAttr(D, AL);
break;
case ParsedAttr::AT_AbiTag:
@@ -9750,28 +6991,28 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
// Swift attributes.
case ParsedAttr::AT_SwiftAsyncName:
- handleSwiftAsyncName(S, D, AL);
+ S.Swift().handleAsyncName(D, AL);
break;
case ParsedAttr::AT_SwiftAttr:
- handleSwiftAttrAttr(S, D, AL);
+ S.Swift().handleAttrAttr(D, AL);
break;
case ParsedAttr::AT_SwiftBridge:
- handleSwiftBridge(S, D, AL);
+ S.Swift().handleBridge(D, AL);
break;
case ParsedAttr::AT_SwiftError:
- handleSwiftError(S, D, AL);
+ S.Swift().handleError(D, AL);
break;
case ParsedAttr::AT_SwiftName:
- handleSwiftName(S, D, AL);
+ S.Swift().handleName(D, AL);
break;
case ParsedAttr::AT_SwiftNewType:
- handleSwiftNewType(S, D, AL);
+ S.Swift().handleNewType(D, AL);
break;
case ParsedAttr::AT_SwiftAsync:
- handleSwiftAsyncAttr(S, D, AL);
+ S.Swift().handleAsyncAttr(D, AL);
break;
case ParsedAttr::AT_SwiftAsyncError:
- handleSwiftAsyncError(S, D, AL);
+ S.Swift().handleAsyncError(D, AL);
break;
// XRay attributes.
@@ -9793,7 +7034,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
break;
case ParsedAttr::AT_ObjCExternallyRetained:
- handleObjCExternallyRetainedAttr(S, D, AL);
+ S.ObjC().handleExternallyRetainedAttr(D, AL);
break;
case ParsedAttr::AT_MIGServerRoutine:
@@ -9805,7 +7046,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
break;
case ParsedAttr::AT_ArmBuiltinAlias:
- handleArmBuiltinAliasAttr(S, D, AL);
+ S.ARM().handleBuiltinAliasAttr(D, AL);
break;
case ParsedAttr::AT_ArmLocallyStreaming:
@@ -9813,7 +7054,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
break;
case ParsedAttr::AT_ArmNew:
- handleArmNewAttr(S, D, AL);
+ S.ARM().handleNewAttr(D, AL);
break;
case ParsedAttr::AT_AcquireHandle:
@@ -9851,11 +7092,17 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_UsingIfExists:
handleSimpleAttribute<UsingIfExistsAttr>(S, D, AL);
break;
+
+ case ParsedAttr::AT_TypeNullable:
+ handleNullableTypeAttr(S, D, AL);
+ break;
+
+ case ParsedAttr::AT_VTablePointerAuthentication:
+ handleVTablePointerAuthentication(S, D, AL);
+ break;
}
}
-/// ProcessDeclAttributeList - Apply all the decl attributes in the specified
-/// attribute list to the specified decl, ignoring any type attributes.
void Sema::ProcessDeclAttributeList(
Scope *S, Decl *D, const ParsedAttributesView &AttrList,
const ProcessDeclAttributeOptions &Options) {
@@ -9929,8 +7176,6 @@ void Sema::ProcessDeclAttributeList(
}
}
-// Helper for delayed processing TransparentUnion or BPFPreserveAccessIndexAttr
-// attribute.
void Sema::ProcessDeclAttributeDelayed(Decl *D,
const ParsedAttributesView &AttrList) {
for (const ParsedAttr &AL : AttrList)
@@ -9942,11 +7187,9 @@ void Sema::ProcessDeclAttributeDelayed(Decl *D,
// For BPFPreserveAccessIndexAttr, we want to populate the attributes
// to fields and inner records as well.
if (D && D->hasAttr<BPFPreserveAccessIndexAttr>())
- handleBPFPreserveAIRecord(*this, cast<RecordDecl>(D));
+ BPF().handlePreserveAIRecord(cast<RecordDecl>(D));
}
-// Annotation attributes are the only attributes allowed after an access
-// specifier.
bool Sema::ProcessAccessDeclAttributeList(
AccessSpecDecl *ASDecl, const ParsedAttributesView &AttrList) {
for (const ParsedAttr &AL : AttrList) {
@@ -9981,9 +7224,6 @@ static void checkUnusedDeclAttributes(Sema &S, const ParsedAttributesView &A) {
}
}
-/// checkUnusedDeclAttributes - Given a declarator which is not being
-/// used to build a declaration, complain about any decl attributes
-/// which might be lying around on it.
void Sema::checkUnusedDeclAttributes(Declarator &D) {
::checkUnusedDeclAttributes(*this, D.getDeclarationAttributes());
::checkUnusedDeclAttributes(*this, D.getDeclSpec().getAttributes());
@@ -9992,8 +7232,6 @@ void Sema::checkUnusedDeclAttributes(Declarator &D) {
::checkUnusedDeclAttributes(*this, D.getTypeObject(i).getAttrs());
}
-/// DeclClonePragmaWeak - clone existing decl (maybe definition),
-/// \#pragma weak needs a non-definition decl and source may not have one.
NamedDecl *Sema::DeclClonePragmaWeak(NamedDecl *ND, const IdentifierInfo *II,
SourceLocation Loc) {
assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND));
@@ -10038,8 +7276,6 @@ NamedDecl *Sema::DeclClonePragmaWeak(NamedDecl *ND, const IdentifierInfo *II,
return NewD;
}
-/// DeclApplyPragmaWeak - A declaration (maybe definition) needs \#pragma weak
-/// applied to it, possibly with an alias.
void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, const WeakInfo &W) {
if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
IdentifierInfo *NDId = ND->getIdentifier();
@@ -10095,29 +7331,37 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
// Ordering of attributes can be important, so we take care to process
// attributes in the order in which they appeared in the source code.
+ auto ProcessAttributesWithSliding =
+ [&](const ParsedAttributesView &Src,
+ const ProcessDeclAttributeOptions &Options) {
+ ParsedAttributesView NonSlidingAttrs;
+ for (ParsedAttr &AL : Src) {
+ // FIXME: this sliding is specific to standard attributes and should
+ // eventually be deprecated and removed as those are not intended to
+ // slide to anything.
+ if ((AL.isStandardAttributeSyntax() || AL.isAlignas()) &&
+ AL.slidesFromDeclToDeclSpecLegacyBehavior()) {
+ // Skip processing the attribute, but do check if it appertains to
+ // the declaration. This is needed for the `MatrixType` attribute,
+ // which, despite being a type attribute, defines a `SubjectList`
+ // that only allows it to be used on typedef declarations.
+ AL.diagnoseAppertainsTo(*this, D);
+ } else {
+ NonSlidingAttrs.addAtEnd(&AL);
+ }
+ }
+ ProcessDeclAttributeList(S, D, NonSlidingAttrs, Options);
+ };
+
// First, process attributes that appeared on the declaration itself (but
// only if they don't have the legacy behavior of "sliding" to the DeclSepc).
- ParsedAttributesView NonSlidingAttrs;
- for (ParsedAttr &AL : PD.getDeclarationAttributes()) {
- if (AL.slidesFromDeclToDeclSpecLegacyBehavior()) {
- // Skip processing the attribute, but do check if it appertains to the
- // declaration. This is needed for the `MatrixType` attribute, which,
- // despite being a type attribute, defines a `SubjectList` that only
- // allows it to be used on typedef declarations.
- AL.diagnoseAppertainsTo(*this, D);
- } else {
- NonSlidingAttrs.addAtEnd(&AL);
- }
- }
- ProcessDeclAttributeList(S, D, NonSlidingAttrs);
+ ProcessAttributesWithSliding(PD.getDeclarationAttributes(), {});
// Apply decl attributes from the DeclSpec if present.
- if (!PD.getDeclSpec().getAttributes().empty()) {
- ProcessDeclAttributeList(S, D, PD.getDeclSpec().getAttributes(),
- ProcessDeclAttributeOptions()
- .WithIncludeCXX11Attributes(false)
- .WithIgnoreTypeAttributes(true));
- }
+ ProcessAttributesWithSliding(PD.getDeclSpec().getAttributes(),
+ ProcessDeclAttributeOptions()
+ .WithIncludeCXX11Attributes(false)
+ .WithIgnoreTypeAttributes(true));
// Walk the declarator structure, applying decl attributes that were in a type
// position to the decl itself. This handles cases like:
@@ -10135,6 +7379,9 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
// Apply additional attributes specified by '#pragma clang attribute'.
AddPragmaAttributes(S, D);
+
+ // Look for API notes that map to attributes.
+ ProcessAPINotes(D);
}
/// Is the given declaration allowed to use a forbidden type?
@@ -10255,9 +7502,6 @@ void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
} while ((pool = pool->getParent()));
}
-/// Given a set of delayed diagnostics, re-emit them as if they had
-/// been delayed in the current context instead of in the given pool.
-/// Essentially, this just moves them to the current pool.
void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) {
DelayedDiagnosticPool *curPool = DelayedDiagnostics.getCurrentPool();
assert(curPool && "re-emitting in undelayed context not supported");