[clang] 6b755b0 - [clang] Split up `SemaDeclAttr.cpp` (#93966)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 4 22:46:42 PDT 2024
Author: Vlad Serebrennikov
Date: 2024-06-05T09:46:37+04:00
New Revision: 6b755b0cf4ddfdc14b0371fd6e361c9b6d0ff702
URL: https://github.com/llvm/llvm-project/commit/6b755b0cf4ddfdc14b0371fd6e361c9b6d0ff702
DIFF: https://github.com/llvm/llvm-project/commit/6b755b0cf4ddfdc14b0371fd6e361c9b6d0ff702.diff
LOG: [clang] Split up `SemaDeclAttr.cpp` (#93966)
This patch moves language- and target-specific functions out of
`SemaDeclAttr.cpp`. As a consequence, `SemaAVR`, `SemaM68k`,
`SemaMSP430`, `SemaOpenCL`, `SemaSwift` were created (but they are not
the only languages and targets affected).
Notable things are that `Sema.h` actually grew a bit, because of
templated helpers that rely on `Sema` that I had to make available from
outside of `SemaDeclAttr.cpp`. I also had to left CUDA-related in
`SemaDeclAttr.cpp`, because it looks like HIP is building up on top of
CUDA attributes.
This is a follow-up to #93179 and continuation of efforts to split
`Sema` up. Additional context can be found in #84184 and #92682.
Added:
clang/include/clang/Sema/SemaAVR.h
clang/include/clang/Sema/SemaM68k.h
clang/include/clang/Sema/SemaMSP430.h
clang/include/clang/Sema/SemaOpenCL.h
clang/include/clang/Sema/SemaSwift.h
clang/lib/Sema/SemaAVR.cpp
clang/lib/Sema/SemaM68k.cpp
clang/lib/Sema/SemaMSP430.cpp
clang/lib/Sema/SemaOpenCL.cpp
clang/lib/Sema/SemaSwift.cpp
Modified:
clang/include/clang/Sema/Attr.h
clang/include/clang/Sema/Sema.h
clang/include/clang/Sema/SemaARM.h
clang/include/clang/Sema/SemaBPF.h
clang/include/clang/Sema/SemaHLSL.h
clang/include/clang/Sema/SemaMIPS.h
clang/include/clang/Sema/SemaObjC.h
clang/include/clang/Sema/SemaOpenMP.h
clang/include/clang/Sema/SemaRISCV.h
clang/include/clang/Sema/SemaSYCL.h
clang/include/clang/Sema/SemaX86.h
clang/lib/Sema/CMakeLists.txt
clang/lib/Sema/Sema.cpp
clang/lib/Sema/SemaAPINotes.cpp
clang/lib/Sema/SemaARM.cpp
clang/lib/Sema/SemaBPF.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/lib/Sema/SemaHLSL.cpp
clang/lib/Sema/SemaMIPS.cpp
clang/lib/Sema/SemaObjC.cpp
clang/lib/Sema/SemaOpenMP.cpp
clang/lib/Sema/SemaRISCV.cpp
clang/lib/Sema/SemaSYCL.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/lib/Sema/SemaType.cpp
clang/lib/Sema/SemaX86.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Sema/Attr.h b/clang/include/clang/Sema/Attr.h
index 1133862568a6c..3f0b10212789a 100644
--- a/clang/include/clang/Sema/Attr.h
+++ b/clang/include/clang/Sema/Attr.h
@@ -13,8 +13,17 @@
#ifndef LLVM_CLANG_SEMA_ATTR_H
#define LLVM_CLANG_SEMA_ATTR_H
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/AttributeCommonInfo.h"
+#include "clang/Basic/DiagnosticSema.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Sema/ParsedAttr.h"
+#include "clang/Sema/SemaBase.h"
#include "llvm/Support/Casting.h"
namespace clang {
@@ -32,5 +41,152 @@ inline bool isFunctionOrMethodOrBlockForAttrSubject(const Decl *D) {
return isFuncOrMethodForAttrSubject(D) || llvm::isa<BlockDecl>(D);
}
+/// Return true if the given decl has a declarator that should have
+/// been processed by Sema::GetTypeForDeclarator.
+inline 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
+/// isFuncOrMethodForAttrSubject or isFunctionOrMethodOrBlockForAttrSubject.
+inline 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).
+inline 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();
+}
+
+inline 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;
+}
+
+inline 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();
+}
+
+inline SourceRange getFunctionOrMethodParamRange(const Decl *D, unsigned Idx) {
+ if (auto *PVD = getFunctionOrMethodParam(D, Idx))
+ return PVD->getSourceRange();
+ return SourceRange();
+}
+
+inline QualType getFunctionOrMethodResultType(const Decl *D) {
+ if (const FunctionType *FnTy = D->getFunctionType())
+ return FnTy->getReturnType();
+ return cast<ObjCMethodDecl>(D)->getReturnType();
+}
+
+inline 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();
+}
+
+inline 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();
+}
+
+inline bool isInstanceMethod(const Decl *D) {
+ if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(D))
+ return MethodDecl->isInstance();
+ return false;
+}
+
+/// Diagnose mutually exclusive attributes when present on a given
+/// declaration. Returns true if diagnosed.
+template <typename AttrTy>
+bool checkAttrMutualExclusion(SemaBase &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>
+bool checkAttrMutualExclusion(SemaBase &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());
+ Diag(A->getLocation(), diag::note_conflicting_attribute);
+ return true;
+ }
+ return false;
+}
+
+template <typename... DiagnosticArgs>
+const SemaBase::SemaDiagnosticBuilder &
+appendDiagnostics(const SemaBase::SemaDiagnosticBuilder &Bldr) {
+ return Bldr;
+}
+
+template <typename T, typename... DiagnosticArgs>
+const SemaBase::SemaDiagnosticBuilder &
+appendDiagnostics(const SemaBase::SemaDiagnosticBuilder &Bldr, T &&ExtraArg,
+ DiagnosticArgs &&...ExtraArgs) {
+ return appendDiagnostics(Bldr << std::forward<T>(ExtraArg),
+ std::forward<DiagnosticArgs>(ExtraArgs)...);
+}
+
+/// Applies the given attribute to the Decl without performing any
+/// additional semantic checking.
+template <typename AttrType>
+void handleSimpleAttribute(SemaBase &S, Decl *D,
+ const AttributeCommonInfo &CI) {
+ D->addAttr(::new (S.getASTContext()) AttrType(S.getASTContext(), CI));
+}
+
+/// 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>
+void handleSimpleAttributeOrDiagnose(SemaBase &S, Decl *D,
+ const AttributeCommonInfo &CI,
+ bool PassesCheck, unsigned DiagID,
+ DiagnosticArgs &&...ExtraArgs) {
+ if (!PassesCheck) {
+ SemaBase::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID);
+ appendDiagnostics(DB, std::forward<DiagnosticArgs>(ExtraArgs)...);
+ return;
+ }
+ handleSimpleAttribute<AttrType>(S, D, CI);
+}
+
} // namespace clang
#endif // LLVM_CLANG_SEMA_ATTR_H
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 7dea2b6826cfd..4d4579fcfd456 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -47,6 +47,7 @@
#include "clang/Basic/TemplateKinds.h"
#include "clang/Basic/TypeTraits.h"
#include "clang/Sema/AnalysisBasedWarnings.h"
+#include "clang/Sema/Attr.h"
#include "clang/Sema/CleanupInfo.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ExternalSemaSource.h"
@@ -171,21 +172,26 @@ class PseudoObjectExpr;
class QualType;
class SemaAMDGPU;
class SemaARM;
+class SemaAVR;
class SemaBPF;
class SemaCodeCompletion;
class SemaCUDA;
class SemaHLSL;
class SemaHexagon;
class SemaLoongArch;
+class SemaM68k;
class SemaMIPS;
+class SemaMSP430;
class SemaNVPTX;
class SemaObjC;
class SemaOpenACC;
+class SemaOpenCL;
class SemaOpenMP;
class SemaPPC;
class SemaPseudoObject;
class SemaRISCV;
class SemaSYCL;
+class SemaSwift;
class SemaSystemZ;
class SemaWasm;
class SemaX86;
@@ -1011,6 +1017,11 @@ class Sema final : public SemaBase {
return *ARMPtr;
}
+ SemaAVR &AVR() {
+ assert(AVRPtr);
+ return *AVRPtr;
+ }
+
SemaBPF &BPF() {
assert(BPFPtr);
return *BPFPtr;
@@ -1041,11 +1052,21 @@ class Sema final : public SemaBase {
return *LoongArchPtr;
}
+ SemaM68k &M68k() {
+ assert(M68kPtr);
+ return *M68kPtr;
+ }
+
SemaMIPS &MIPS() {
assert(MIPSPtr);
return *MIPSPtr;
}
+ SemaMSP430 &MSP430() {
+ assert(MSP430Ptr);
+ return *MSP430Ptr;
+ }
+
SemaNVPTX &NVPTX() {
assert(NVPTXPtr);
return *NVPTXPtr;
@@ -1061,6 +1082,11 @@ class Sema final : public SemaBase {
return *OpenACCPtr;
}
+ SemaOpenCL &OpenCL() {
+ assert(OpenCLPtr);
+ return *OpenCLPtr;
+ }
+
SemaOpenMP &OpenMP() {
assert(OpenMPPtr && "SemaOpenMP is dead");
return *OpenMPPtr;
@@ -1086,6 +1112,11 @@ class Sema final : public SemaBase {
return *SYCLPtr;
}
+ SemaSwift &Swift() {
+ assert(SwiftPtr);
+ return *SwiftPtr;
+ }
+
SemaSystemZ &SystemZ() {
assert(SystemZPtr);
return *SystemZPtr;
@@ -1133,21 +1164,26 @@ class Sema final : public SemaBase {
std::unique_ptr<SemaAMDGPU> AMDGPUPtr;
std::unique_ptr<SemaARM> ARMPtr;
+ std::unique_ptr<SemaAVR> AVRPtr;
std::unique_ptr<SemaBPF> BPFPtr;
std::unique_ptr<SemaCodeCompletion> CodeCompletionPtr;
std::unique_ptr<SemaCUDA> CUDAPtr;
std::unique_ptr<SemaHLSL> HLSLPtr;
std::unique_ptr<SemaHexagon> HexagonPtr;
std::unique_ptr<SemaLoongArch> LoongArchPtr;
+ std::unique_ptr<SemaM68k> M68kPtr;
std::unique_ptr<SemaMIPS> MIPSPtr;
+ std::unique_ptr<SemaMSP430> MSP430Ptr;
std::unique_ptr<SemaNVPTX> NVPTXPtr;
std::unique_ptr<SemaObjC> ObjCPtr;
std::unique_ptr<SemaOpenACC> OpenACCPtr;
+ std::unique_ptr<SemaOpenCL> OpenCLPtr;
std::unique_ptr<SemaOpenMP> OpenMPPtr;
std::unique_ptr<SemaPPC> PPCPtr;
std::unique_ptr<SemaPseudoObject> PseudoObjectPtr;
std::unique_ptr<SemaRISCV> RISCVPtr;
std::unique_ptr<SemaSYCL> SYCLPtr;
+ std::unique_ptr<SemaSwift> SwiftPtr;
std::unique_ptr<SemaSystemZ> SystemZPtr;
std::unique_ptr<SemaWasm> WasmPtr;
std::unique_ptr<SemaX86> X86Ptr;
@@ -3711,8 +3747,6 @@ class Sema final : public SemaBase {
const AttributeCommonInfo &CI,
const IdentifierInfo *Ident);
MinSizeAttr *mergeMinSizeAttr(Decl *D, const AttributeCommonInfo &CI);
- SwiftNameAttr *mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA,
- StringRef Name);
OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D,
const AttributeCommonInfo &CI);
InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, const ParsedAttr &AL);
@@ -3726,8 +3760,6 @@ class Sema final : public SemaBase {
const ParsedAttr &attr, CallingConv &CC, const FunctionDecl *FD = nullptr,
CUDAFunctionTarget CFT = CUDAFunctionTarget::InvalidTarget);
- void AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI,
- ParameterABI ABI);
bool CheckRegparmAttr(const ParsedAttr &attr, unsigned &value);
/// Create an CUDALaunchBoundsAttr attribute.
@@ -3742,20 +3774,6 @@ class Sema final : public SemaBase {
Expr *MaxThreads, Expr *MinBlocks, Expr *MaxBlocks);
enum class RetainOwnershipKind { NS, CF, OS };
- void AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI,
- RetainOwnershipKind K, bool IsTemplateInstantiation);
-
- bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type);
-
- /// Do a check to make sure \p Name looks like a legal argument for the
- /// swift_name attribute applied to decl \p D. Raise a diagnostic if the name
- /// is invalid for the given declaration.
- ///
- /// \p AL is used to provide caret diagnostics in case of a malformed name.
- ///
- /// \returns true if the name is a valid swift name for \p D, false otherwise.
- bool DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc,
- const ParsedAttr &AL, bool IsAsync);
UuidAttr *mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI,
StringRef UuidAsWritten, MSGuidDecl *GuidDecl);
@@ -3825,6 +3843,52 @@ class Sema final : public SemaBase {
void redelayDiagnostics(sema::DelayedDiagnosticPool &pool);
+ /// 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>
+ bool checkFunctionOrMethodParameterIndex(const Decl *D, const AttrInfo &AI,
+ unsigned AttrArgNum,
+ const Expr *IdxExpr, ParamIdx &Idx,
+ bool CanIndexImplicitThis = false) {
+ assert(isFunctionOrMethodOrBlockForAttrSubject(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(Context))) {
+ 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)) {
+ Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds)
+ << &AI << AttrArgNum << IdxExpr->getSourceRange();
+ return false;
+ }
+ if (HasImplicitThisParam && !CanIndexImplicitThis) {
+ if (IdxSource == 1) {
+ Diag(getAttrLoc(AI), diag::err_attribute_invalid_implicit_this_argument)
+ << &AI << IdxExpr->getSourceRange();
+ return false;
+ }
+ }
+
+ Idx = ParamIdx(IdxSource, D);
+ return true;
+ }
+
///@}
//
diff --git a/clang/include/clang/Sema/SemaARM.h b/clang/include/clang/Sema/SemaARM.h
index 02698a33abd55..6478c0beb715d 100644
--- a/clang/include/clang/Sema/SemaARM.h
+++ b/clang/include/clang/Sema/SemaARM.h
@@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_SEMA_SEMAARM_H
#define LLVM_CLANG_SEMA_SEMAARM_H
+#include "clang/AST/DeclBase.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/SemaBase.h"
@@ -20,6 +21,7 @@
#include <tuple>
namespace clang {
+class ParsedAttr;
class SemaARM : public SemaBase {
public:
@@ -54,6 +56,15 @@ class SemaARM : public SemaBase {
bool BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, int ArgNum,
unsigned ExpectedFieldNum, bool AllowName);
bool BuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall);
+
+ bool MveAliasValid(unsigned BuiltinID, StringRef AliasName);
+ bool CdeAliasValid(unsigned BuiltinID, StringRef AliasName);
+ bool SveAliasValid(unsigned BuiltinID, StringRef AliasName);
+ bool SmeAliasValid(unsigned BuiltinID, StringRef AliasName);
+ void handleBuiltinAliasAttr(Decl *D, const ParsedAttr &AL);
+ void handleNewAttr(Decl *D, const ParsedAttr &AL);
+ void handleCmseNSEntryAttr(Decl *D, const ParsedAttr &AL);
+ void handleInterruptAttr(Decl *D, const ParsedAttr &AL);
};
SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD);
diff --git a/clang/include/clang/Sema/SemaAVR.h b/clang/include/clang/Sema/SemaAVR.h
new file mode 100644
index 0000000000000..708da3a6026ac
--- /dev/null
+++ b/clang/include/clang/Sema/SemaAVR.h
@@ -0,0 +1,32 @@
+//===----- SemaAVR.h ------- AVR target-specific routines -----*- C++ -*---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file declares semantic analysis functions specific to AVR.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_SEMAAVR_H
+#define LLVM_CLANG_SEMA_SEMAAVR_H
+
+#include "clang/Sema/SemaBase.h"
+
+namespace clang {
+class Decl;
+class ParsedAttr;
+
+class SemaAVR : public SemaBase {
+public:
+ SemaAVR(Sema &S);
+
+ void handleInterruptAttr(Decl *D, const ParsedAttr &AL);
+ void handleSignalAttr(Decl *D, const ParsedAttr &AL);
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_SEMA_SEMAAVR_H
diff --git a/clang/include/clang/Sema/SemaBPF.h b/clang/include/clang/Sema/SemaBPF.h
index a3bf59128d254..0182ccfe508a7 100644
--- a/clang/include/clang/Sema/SemaBPF.h
+++ b/clang/include/clang/Sema/SemaBPF.h
@@ -13,15 +13,22 @@
#ifndef LLVM_CLANG_SEMA_SEMABPF_H
#define LLVM_CLANG_SEMA_SEMABPF_H
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
#include "clang/AST/Expr.h"
#include "clang/Sema/SemaBase.h"
namespace clang {
+class ParsedAttr;
+
class SemaBPF : public SemaBase {
public:
SemaBPF(Sema &S);
bool CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
+
+ void handlePreserveAIRecord(RecordDecl *RD);
+ void handlePreserveAccessIndexAttr(Decl *D, const ParsedAttr &AL);
};
} // namespace clang
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index eac1f7c07c85d..e145f5e7f43f8 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -25,6 +25,7 @@
#include <initializer_list>
namespace clang {
+class ParsedAttr;
class SemaHLSL : public SemaBase {
public:
@@ -50,6 +51,13 @@ class SemaHLSL : public SemaBase {
const Attr *A, HLSLShaderAttr::ShaderType Stage,
std::initializer_list<HLSLShaderAttr::ShaderType> AllowedStages);
void DiagnoseAvailabilityViolations(TranslationUnitDecl *TU);
+
+ void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL);
+ void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL);
+ void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL);
+ void handleShaderAttr(Decl *D, const ParsedAttr &AL);
+ void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL);
+ void handleParamModifierAttr(Decl *D, const ParsedAttr &AL);
};
} // namespace clang
diff --git a/clang/include/clang/Sema/SemaM68k.h b/clang/include/clang/Sema/SemaM68k.h
new file mode 100644
index 0000000000000..5a9767d5ea521
--- /dev/null
+++ b/clang/include/clang/Sema/SemaM68k.h
@@ -0,0 +1,30 @@
+//===----- SemaM68k.h ------ M68k target-specific routines ----*- C++ -*---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file declares semantic analysis functions specific to M68k.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_SEMAM68K_H
+#define LLVM_CLANG_SEMA_SEMAM68K_H
+
+#include "clang/Sema/SemaBase.h"
+
+namespace clang {
+class Decl;
+class ParsedAttr;
+
+class SemaM68k : public SemaBase {
+public:
+ SemaM68k(Sema &S);
+
+ void handleInterruptAttr(Decl *D, const ParsedAttr &AL);
+};
+} // namespace clang
+
+#endif // LLVM_CLANG_SEMA_SEMAM68K_H
diff --git a/clang/include/clang/Sema/SemaMIPS.h b/clang/include/clang/Sema/SemaMIPS.h
index 3f1781b36efd9..6366dce57626a 100644
--- a/clang/include/clang/Sema/SemaMIPS.h
+++ b/clang/include/clang/Sema/SemaMIPS.h
@@ -13,11 +13,14 @@
#ifndef LLVM_CLANG_SEMA_SEMAMIPS_H
#define LLVM_CLANG_SEMA_SEMAMIPS_H
+#include "clang/AST/DeclBase.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/SemaBase.h"
namespace clang {
+class ParsedAttr;
+
class SemaMIPS : public SemaBase {
public:
SemaMIPS(Sema &S);
@@ -27,6 +30,7 @@ class SemaMIPS : public SemaBase {
bool CheckMipsBuiltinCpu(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
bool CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall);
+ void handleInterruptAttr(Decl *D, const ParsedAttr &AL);
};
} // namespace clang
diff --git a/clang/include/clang/Sema/SemaMSP430.h b/clang/include/clang/Sema/SemaMSP430.h
new file mode 100644
index 0000000000000..e1034aefe8816
--- /dev/null
+++ b/clang/include/clang/Sema/SemaMSP430.h
@@ -0,0 +1,30 @@
+//===----- SemaMSP430.h --- MSP430 target-specific routines ---*- C++ -*---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file declares semantic analysis functions specific to MSP430.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_SEMAMSP430_H
+#define LLVM_CLANG_SEMA_SEMAMSP430_H
+
+#include "clang/Sema/SemaBase.h"
+
+namespace clang {
+class Decl;
+class ParsedAttr;
+
+class SemaMSP430 : public SemaBase {
+public:
+ SemaMSP430(Sema &S);
+
+ void handleInterruptAttr(Decl *D, const ParsedAttr &AL);
+};
+} // namespace clang
+
+#endif // LLVM_CLANG_SEMA_SEMAMSP430_H
diff --git a/clang/include/clang/Sema/SemaObjC.h b/clang/include/clang/Sema/SemaObjC.h
index a9a0d16780956..91430797e5ed8 100644
--- a/clang/include/clang/Sema/SemaObjC.h
+++ b/clang/include/clang/Sema/SemaObjC.h
@@ -30,7 +30,6 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ObjCMethodList.h"
#include "clang/Sema/Ownership.h"
-#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Redeclaration.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaBase.h"
@@ -45,6 +44,7 @@
namespace clang {
enum class CheckedConversionKind;
+class ParsedAttr;
struct SkipBodyInfo;
class SemaObjC : public SemaBase {
@@ -1007,6 +1007,56 @@ class SemaObjC : public SemaBase {
ObjCInterfaceDecl *IDecl);
///@}
+
+ //
+ //
+ // -------------------------------------------------------------------------
+ //
+ //
+
+ /// \name ObjC Attributes
+ /// Implementations are in SemaObjC.cpp
+ ///@{
+
+ bool isNSStringType(QualType T, bool AllowNSAttributedString = false);
+ bool isCFStringType(QualType T);
+
+ void handleIBOutlet(Decl *D, const ParsedAttr &AL);
+ void handleIBOutletCollection(Decl *D, const ParsedAttr &AL);
+
+ void handleSuppresProtocolAttr(Decl *D, const ParsedAttr &AL);
+ void handleDirectAttr(Decl *D, const ParsedAttr &AL);
+ void handleDirectMembersAttr(Decl *D, const ParsedAttr &AL);
+ void handleMethodFamilyAttr(Decl *D, const ParsedAttr &AL);
+ void handleNSObject(Decl *D, const ParsedAttr &AL);
+ void handleIndependentClass(Decl *D, const ParsedAttr &AL);
+ void handleBlocksAttr(Decl *D, const ParsedAttr &AL);
+ void handleReturnsInnerPointerAttr(Decl *D, const ParsedAttr &Attrs);
+ void handleXReturnsXRetainedAttr(Decl *D, const ParsedAttr &AL);
+ void handleRequiresSuperAttr(Decl *D, const ParsedAttr &Attrs);
+ void handleNSErrorDomain(Decl *D, const ParsedAttr &Attr);
+ void handleBridgeAttr(Decl *D, const ParsedAttr &AL);
+ void handleBridgeMutableAttr(Decl *D, const ParsedAttr &AL);
+ void handleBridgeRelatedAttr(Decl *D, const ParsedAttr &AL);
+ void handleDesignatedInitializer(Decl *D, const ParsedAttr &AL);
+ void handleRuntimeName(Decl *D, const ParsedAttr &AL);
+ void handleBoxable(Decl *D, const ParsedAttr &AL);
+ void handleOwnershipAttr(Decl *D, const ParsedAttr &AL);
+ void handlePreciseLifetimeAttr(Decl *D, const ParsedAttr &AL);
+ void handleExternallyRetainedAttr(Decl *D, const ParsedAttr &AL);
+
+ void AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI,
+ Sema::RetainOwnershipKind K,
+ bool IsTemplateInstantiation);
+
+ /// \return whether the parameter is a pointer to OSObject pointer.
+ bool isValidOSObjectOutParameter(const Decl *D);
+ bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type);
+
+ Sema::RetainOwnershipKind
+ parsedAttrToRetainOwnershipKind(const ParsedAttr &AL);
+
+ ///@}
};
} // namespace clang
diff --git a/clang/include/clang/Sema/SemaOpenCL.h b/clang/include/clang/Sema/SemaOpenCL.h
new file mode 100644
index 0000000000000..0d80c4b4c0b56
--- /dev/null
+++ b/clang/include/clang/Sema/SemaOpenCL.h
@@ -0,0 +1,35 @@
+//===----- SemaOpenCL.h --- Semantic Analysis for OpenCL constructs -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file declares semantic analysis routines for OpenCL.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_SEMAOPENCL_H
+#define LLVM_CLANG_SEMA_SEMAOPENCL_H
+
+#include "clang/Sema/SemaBase.h"
+
+namespace clang {
+class Decl;
+class ParsedAttr;
+
+class SemaOpenCL : public SemaBase {
+public:
+ SemaOpenCL(Sema &S);
+
+ void handleNoSVMAttr(Decl *D, const ParsedAttr &AL);
+ void handleAccessAttr(Decl *D, const ParsedAttr &AL);
+
+ // Handles intel_reqd_sub_group_size.
+ void handleSubGroupSize(Decl *D, const ParsedAttr &AL);
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_SEMA_SEMAOPENCL_H
diff --git a/clang/include/clang/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h
index 51981e1c9a8b9..3edf1cc7c12f2 100644
--- a/clang/include/clang/Sema/SemaOpenMP.h
+++ b/clang/include/clang/Sema/SemaOpenMP.h
@@ -42,6 +42,7 @@
#include <utility>
namespace clang {
+class ParsedAttr;
class SemaOpenMP : public SemaBase {
public:
@@ -1348,6 +1349,8 @@ class SemaOpenMP : public SemaBase {
SourceLocation LLoc, SourceLocation RLoc,
ArrayRef<OMPIteratorData> Data);
+ void handleOMPAssumeAttr(Decl *D, const ParsedAttr &AL);
+
private:
void *VarDataSharingAttributesStack;
diff --git a/clang/include/clang/Sema/SemaRISCV.h b/clang/include/clang/Sema/SemaRISCV.h
index b6dd81f8d4d80..48d15c411bddd 100644
--- a/clang/include/clang/Sema/SemaRISCV.h
+++ b/clang/include/clang/Sema/SemaRISCV.h
@@ -24,6 +24,8 @@
#include <memory>
namespace clang {
+class ParsedAttr;
+
class SemaRISCV : public SemaBase {
public:
SemaRISCV(Sema &S);
@@ -36,6 +38,9 @@ class SemaRISCV : public SemaBase {
bool isValidRVVBitcast(QualType srcType, QualType destType);
+ void handleInterruptAttr(Decl *D, const ParsedAttr &AL);
+ bool isAliasValid(unsigned BuiltinID, StringRef AliasName);
+
/// Indicate RISC-V vector builtin functions enabled or not.
bool DeclareRVVBuiltins = false;
diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h
index f0dcb92ee9ab3..363178546a236 100644
--- a/clang/include/clang/Sema/SemaSYCL.h
+++ b/clang/include/clang/Sema/SemaSYCL.h
@@ -21,6 +21,8 @@
#include "llvm/ADT/DenseSet.h"
namespace clang {
+class Decl;
+class ParsedAttr;
class SemaSYCL : public SemaBase {
public:
@@ -58,6 +60,8 @@ class SemaSYCL : public SemaBase {
SourceLocation LParen,
SourceLocation RParen,
ParsedType ParsedTy);
+
+ void handleKernelAttr(Decl *D, const ParsedAttr &AL);
};
} // namespace clang
diff --git a/clang/include/clang/Sema/SemaSwift.h b/clang/include/clang/Sema/SemaSwift.h
new file mode 100644
index 0000000000000..a5561d756affd
--- /dev/null
+++ b/clang/include/clang/Sema/SemaSwift.h
@@ -0,0 +1,59 @@
+//===----- SemaSwift.h --- Swift language-specific routines ---*- C++ -*---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file declares semantic analysis functions specific to Swift.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_SEMASWIFT_H
+#define LLVM_CLANG_SEMA_SEMASWIFT_H
+
+#include "clang/AST/Attr.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Sema/SemaBase.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+class AttributeCommonInfo;
+class Decl;
+class ParsedAttr;
+class SwiftNameAttr;
+
+class SemaSwift : public SemaBase {
+public:
+ SemaSwift(Sema &S);
+
+ SwiftNameAttr *mergeNameAttr(Decl *D, const SwiftNameAttr &SNA,
+ StringRef Name);
+
+ void handleAttrAttr(Decl *D, const ParsedAttr &AL);
+ void handleAsyncAttr(Decl *D, const ParsedAttr &AL);
+ void handleBridge(Decl *D, const ParsedAttr &AL);
+ void handleError(Decl *D, const ParsedAttr &AL);
+ void handleAsyncError(Decl *D, const ParsedAttr &AL);
+ void handleName(Decl *D, const ParsedAttr &AL);
+ void handleAsyncName(Decl *D, const ParsedAttr &AL);
+ void handleNewType(Decl *D, const ParsedAttr &AL);
+
+ /// Do a check to make sure \p Name looks like a legal argument for the
+ /// swift_name attribute applied to decl \p D. Raise a diagnostic if the name
+ /// is invalid for the given declaration.
+ ///
+ /// \p AL is used to provide caret diagnostics in case of a malformed name.
+ ///
+ /// \returns true if the name is a valid swift name for \p D, false otherwise.
+ bool DiagnoseName(Decl *D, StringRef Name, SourceLocation Loc,
+ const ParsedAttr &AL, bool IsAsync);
+ void AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI,
+ ParameterABI abi);
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_SEMA_SEMASWIFT_H
diff --git a/clang/include/clang/Sema/SemaX86.h b/clang/include/clang/Sema/SemaX86.h
index e322483294ec7..e53aaf229c38d 100644
--- a/clang/include/clang/Sema/SemaX86.h
+++ b/clang/include/clang/Sema/SemaX86.h
@@ -13,12 +13,15 @@
#ifndef LLVM_CLANG_SEMA_SEMAX86_H
#define LLVM_CLANG_SEMA_SEMAX86_H
+#include "clang/AST/DeclBase.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/SemaBase.h"
namespace clang {
+class ParsedAttr;
+
class SemaX86 : public SemaBase {
public:
SemaX86(Sema &S);
@@ -32,6 +35,9 @@ class SemaX86 : public SemaBase {
ArrayRef<int> ArgNums);
bool CheckBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
+
+ void handleAnyInterruptAttr(Decl *D, const ParsedAttr &AL);
+ void handleForceAlignArgPointerAttr(Decl *D, const ParsedAttr &AL);
};
} // namespace clang
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index c9abf58fcbd29..f152d243d39a5 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -28,6 +28,7 @@ add_clang_library(clangSema
Sema.cpp
SemaAMDGPU.cpp
SemaARM.cpp
+ SemaAVR.cpp
SemaAccess.cpp
SemaAttr.cpp
SemaAPINotes.cpp
@@ -58,12 +59,15 @@ add_clang_library(clangSema
SemaLambda.cpp
SemaLookup.cpp
SemaLoongArch.cpp
+ SemaM68k.cpp
SemaMIPS.cpp
+ SemaMSP430.cpp
SemaModule.cpp
SemaNVPTX.cpp
SemaObjC.cpp
SemaObjCProperty.cpp
SemaOpenACC.cpp
+ SemaOpenCL.cpp
SemaOpenMP.cpp
SemaOverload.cpp
SemaPPC.cpp
@@ -73,6 +77,7 @@ add_clang_library(clangSema
SemaStmtAsm.cpp
SemaStmtAttr.cpp
SemaSYCL.cpp
+ SemaSwift.cpp
SemaSystemZ.cpp
SemaTemplate.cpp
SemaTemplateDeduction.cpp
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 582adcfa84c46..a612dcd4b4d03 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -43,6 +43,7 @@
#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/SemaCodeCompletion.h"
@@ -51,15 +52,19 @@
#include "clang/Sema/SemaHexagon.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLoongArch.h"
+#include "clang/Sema/SemaM68k.h"
#include "clang/Sema/SemaMIPS.h"
+#include "clang/Sema/SemaMSP430.h"
#include "clang/Sema/SemaNVPTX.h"
#include "clang/Sema/SemaObjC.h"
#include "clang/Sema/SemaOpenACC.h"
+#include "clang/Sema/SemaOpenCL.h"
#include "clang/Sema/SemaOpenMP.h"
#include "clang/Sema/SemaPPC.h"
#include "clang/Sema/SemaPseudoObject.h"
#include "clang/Sema/SemaRISCV.h"
#include "clang/Sema/SemaSYCL.h"
+#include "clang/Sema/SemaSwift.h"
#include "clang/Sema/SemaSystemZ.h"
#include "clang/Sema/SemaWasm.h"
#include "clang/Sema/SemaX86.h"
@@ -218,6 +223,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
CurScope(nullptr), Ident_super(nullptr),
AMDGPUPtr(std::make_unique<SemaAMDGPU>(*this)),
ARMPtr(std::make_unique<SemaARM>(*this)),
+ AVRPtr(std::make_unique<SemaAVR>(*this)),
BPFPtr(std::make_unique<SemaBPF>(*this)),
CodeCompletionPtr(
std::make_unique<SemaCodeCompletion>(*this, CodeCompleter)),
@@ -225,15 +231,19 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
HLSLPtr(std::make_unique<SemaHLSL>(*this)),
HexagonPtr(std::make_unique<SemaHexagon>(*this)),
LoongArchPtr(std::make_unique<SemaLoongArch>(*this)),
+ M68kPtr(std::make_unique<SemaM68k>(*this)),
MIPSPtr(std::make_unique<SemaMIPS>(*this)),
+ MSP430Ptr(std::make_unique<SemaMSP430>(*this)),
NVPTXPtr(std::make_unique<SemaNVPTX>(*this)),
ObjCPtr(std::make_unique<SemaObjC>(*this)),
OpenACCPtr(std::make_unique<SemaOpenACC>(*this)),
+ OpenCLPtr(std::make_unique<SemaOpenCL>(*this)),
OpenMPPtr(std::make_unique<SemaOpenMP>(*this)),
PPCPtr(std::make_unique<SemaPPC>(*this)),
PseudoObjectPtr(std::make_unique<SemaPseudoObject>(*this)),
RISCVPtr(std::make_unique<SemaRISCV>(*this)),
SYCLPtr(std::make_unique<SemaSYCL>(*this)),
+ SwiftPtr(std::make_unique<SemaSwift>(*this)),
SystemZPtr(std::make_unique<SemaSystemZ>(*this)),
WasmPtr(std::make_unique<SemaWasm>(*this)),
X86Ptr(std::make_unique<SemaX86>(*this)),
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index c80b08e361cfa..bc1628f5b7163 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -17,6 +17,7 @@
#include "clang/Lex/Lexer.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaObjC.h"
+#include "clang/Sema/SemaSwift.h"
using namespace clang;
@@ -303,8 +304,8 @@ static void ProcessAPINotes(Sema &S, Decl *D,
SourceLocation(), nullptr, nullptr, nullptr,
ParsedAttr::Form::GNU());
- if (!S.DiagnoseSwiftName(D, Info.SwiftName, D->getLocation(), *SNA,
- /*IsAsync=*/false))
+ if (!S.Swift().DiagnoseName(D, Info.SwiftName, D->getLocation(), *SNA,
+ /*IsAsync=*/false))
return nullptr;
return new (S.Context)
diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp
index da37ccef051a6..02e68dbdb2e9d 100644
--- a/clang/lib/Sema/SemaARM.cpp
+++ b/clang/lib/Sema/SemaARM.cpp
@@ -14,6 +14,7 @@
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Sema/Initialization.h"
+#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Sema.h"
namespace clang {
@@ -1085,4 +1086,199 @@ bool SemaARM::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI,
return SemaRef.BuiltinConstantArgRange(TheCall, i, l, u + l);
}
+namespace {
+struct IntrinToName {
+ uint32_t Id;
+ int32_t FullName;
+ int32_t ShortName;
+};
+} // unnamed namespace
+
+static bool BuiltinAliasValid(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;
+}
+
+bool SemaARM::MveAliasValid(unsigned BuiltinID, StringRef AliasName) {
+#include "clang/Basic/arm_mve_builtin_aliases.inc"
+ // The included file defines:
+ // - ArrayRef<IntrinToName> Map
+ // - const char IntrinNames[]
+ return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
+}
+
+bool SemaARM::CdeAliasValid(unsigned BuiltinID, StringRef AliasName) {
+#include "clang/Basic/arm_cde_builtin_aliases.inc"
+ return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
+}
+
+bool SemaARM::SveAliasValid(unsigned BuiltinID, StringRef AliasName) {
+ if (getASTContext().BuiltinInfo.isAuxBuiltinID(BuiltinID))
+ BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(BuiltinID);
+ return BuiltinID >= AArch64::FirstSVEBuiltin &&
+ BuiltinID <= AArch64::LastSVEBuiltin;
+}
+
+bool SemaARM::SmeAliasValid(unsigned BuiltinID, StringRef AliasName) {
+ if (getASTContext().BuiltinInfo.isAuxBuiltinID(BuiltinID))
+ BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(BuiltinID);
+ return BuiltinID >= AArch64::FirstSMEBuiltin &&
+ BuiltinID <= AArch64::LastSMEBuiltin;
+}
+
+void SemaARM::handleBuiltinAliasAttr(Decl *D, const ParsedAttr &AL) {
+ ASTContext &Context = getASTContext();
+ if (!AL.isArgIdent(0)) {
+ Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
+ << AL << 1 << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident;
+ unsigned BuiltinID = Ident->getBuiltinID();
+ StringRef AliasName = cast<FunctionDecl>(D)->getIdentifier()->getName();
+
+ bool IsAArch64 = Context.getTargetInfo().getTriple().isAArch64();
+ if ((IsAArch64 && !SveAliasValid(BuiltinID, AliasName) &&
+ !SmeAliasValid(BuiltinID, AliasName)) ||
+ (!IsAArch64 && !MveAliasValid(BuiltinID, AliasName) &&
+ !CdeAliasValid(BuiltinID, AliasName))) {
+ Diag(AL.getLoc(), diag::err_attribute_arm_builtin_alias);
+ return;
+ }
+
+ D->addAttr(::new (Context) ArmBuiltinAliasAttr(Context, AL, Ident));
+}
+
+static bool checkNewAttrMutualExclusion(
+ 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();
+}
+
+void SemaARM::handleNewAttr(Decl *D, const ParsedAttr &AL) {
+ if (!AL.getNumArgs()) {
+ 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 (!SemaRef.checkStringLiteralArgumentAttr(AL, I, StateName, &LiteralLoc))
+ return;
+
+ if (StateName == "za")
+ HasZA = true;
+ else if (StateName == "zt0")
+ HasZT0 = true;
+ else {
+ 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 &&
+ checkNewAttrMutualExclusion(SemaRef, AL, FPT, ZAState, "za"))
+ return;
+ FunctionType::ArmStateValue ZT0State =
+ FunctionType::getArmZT0State(FPT->getAArch64SMEAttributes());
+ if (HasZT0 && ZT0State != FunctionType::ARM_None &&
+ checkNewAttrMutualExclusion(SemaRef, AL, FPT, ZT0State, "zt0"))
+ return;
+ }
+
+ D->dropAttr<ArmNewAttr>();
+ D->addAttr(::new (getASTContext()) ArmNewAttr(
+ getASTContext(), AL, NewState.data(), NewState.size()));
+}
+
+void SemaARM::handleCmseNSEntryAttr(Decl *D, const ParsedAttr &AL) {
+ if (getLangOpts().CPlusPlus && !D->getDeclContext()->isExternCContext()) {
+ Diag(AL.getLoc(), diag::err_attribute_not_clinkage) << AL;
+ return;
+ }
+
+ const auto *FD = cast<FunctionDecl>(D);
+ if (!FD->isExternallyVisible()) {
+ Diag(AL.getLoc(), diag::warn_attribute_cmse_entry_static);
+ return;
+ }
+
+ D->addAttr(::new (getASTContext()) CmseNSEntryAttr(getASTContext(), AL));
+}
+
+void SemaARM::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
+ // Check the attribute arguments.
+ if (AL.getNumArgs() > 1) {
+ Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1;
+ return;
+ }
+
+ StringRef Str;
+ SourceLocation ArgLoc;
+
+ if (AL.getNumArgs() == 0)
+ Str = "";
+ else if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
+ return;
+
+ ARMInterruptAttr::InterruptType Kind;
+ if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
+ Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
+ << AL << Str << ArgLoc;
+ return;
+ }
+
+ D->addAttr(::new (getASTContext())
+ ARMInterruptAttr(getASTContext(), AL, Kind));
+}
+
} // namespace clang
diff --git a/clang/lib/Sema/SemaAVR.cpp b/clang/lib/Sema/SemaAVR.cpp
new file mode 100644
index 0000000000000..47368780b6203
--- /dev/null
+++ b/clang/lib/Sema/SemaAVR.cpp
@@ -0,0 +1,49 @@
+//===------ SemaAVR.cpp ---------- AVR target-specific routines -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis functions specific to AVR.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/SemaAVR.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/Basic/DiagnosticSema.h"
+#include "clang/Sema/Attr.h"
+#include "clang/Sema/ParsedAttr.h"
+#include "clang/Sema/Sema.h"
+
+namespace clang {
+SemaAVR::SemaAVR(Sema &S) : SemaBase(S) {}
+
+void SemaAVR::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
+ if (!isFuncOrMethodForAttrSubject(D)) {
+ Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
+ << AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
+ return;
+ }
+
+ if (!AL.checkExactlyNumArgs(SemaRef, 0))
+ return;
+
+ handleSimpleAttribute<AVRInterruptAttr>(*this, D, AL);
+}
+
+void SemaAVR::handleSignalAttr(Decl *D, const ParsedAttr &AL) {
+ if (!isFuncOrMethodForAttrSubject(D)) {
+ Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
+ << AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
+ return;
+ }
+
+ if (!AL.checkExactlyNumArgs(SemaRef, 0))
+ return;
+
+ handleSimpleAttribute<AVRSignalAttr>(*this, D, AL);
+}
+
+} // namespace clang
diff --git a/clang/lib/Sema/SemaBPF.cpp b/clang/lib/Sema/SemaBPF.cpp
index bde1a26f1ebc0..7c00084d62dd9 100644
--- a/clang/lib/Sema/SemaBPF.cpp
+++ b/clang/lib/Sema/SemaBPF.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/TargetBuiltins.h"
+#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Sema.h"
#include "llvm/ADT/APSInt.h"
#include <optional>
@@ -171,4 +172,23 @@ bool SemaBPF::CheckBPFBuiltinFunctionCall(unsigned BuiltinID,
return false;
}
+void SemaBPF::handlePreserveAIRecord(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(getASTContext()));
+ if (auto *Rec = dyn_cast<RecordDecl>(D))
+ handlePreserveAIRecord(Rec);
+ }
+}
+
+void SemaBPF::handlePreserveAccessIndexAttr(Decl *D, const ParsedAttr &AL) {
+ auto *Rec = cast<RecordDecl>(D);
+ handlePreserveAIRecord(Rec);
+ Rec->addAttr(::new (getASTContext())
+ BPFPreserveAccessIndexAttr(getASTContext(), AL));
+}
+
} // namespace clang
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 7ff05ae514ebe..a6734ef8c30aa 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -52,6 +52,7 @@
#include "clang/Sema/SemaOpenMP.h"
#include "clang/Sema/SemaPPC.h"
#include "clang/Sema/SemaRISCV.h"
+#include "clang/Sema/SemaSwift.h"
#include "clang/Sema/SemaWasm.h"
#include "clang/Sema/Template.h"
#include "llvm/ADT/STLForwardCompat.h"
@@ -2918,7 +2919,7 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
} else if (const auto *MA = dyn_cast<MinSizeAttr>(Attr))
NewAttr = S.mergeMinSizeAttr(D, *MA);
else if (const auto *SNA = dyn_cast<SwiftNameAttr>(Attr))
- NewAttr = S.mergeSwiftNameAttr(D, *SNA, SNA->getName());
+ NewAttr = S.Swift().mergeNameAttr(D, *SNA, SNA->getName());
else if (const auto *OA = dyn_cast<OptimizeNoneAttr>(Attr))
NewAttr = S.mergeOptimizeNoneAttr(D, *OA);
else if (const auto *InternalLinkageA = dyn_cast<InternalLinkageAttr>(Attr))
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 7c1fb23b90728..ce6b5b1ff6f93 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -42,11 +42,23 @@
#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"
@@ -70,128 +82,6 @@ namespace AttributeLangSupport {
};
} // end namespace AttributeLangSupport
-//===----------------------------------------------------------------------===//
-// Helper functions
-//===----------------------------------------------------------------------===//
-
-/// 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
-/// isFuncOrMethodForAttrSubject or isFunctionOrMethodOrBlockForAttrSubject.
-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();
@@ -221,78 +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(isFunctionOrMethodOrBlockForAttrSubject(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(S.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(S.getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds)
- << &AI << AttrArgNum << IdxExpr->getSourceRange();
- return false;
- }
- if (HasImplicitThisParam && !CanIndexImplicitThis) {
- if (IdxSource == 1) {
- S.Diag(S.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.
@@ -348,45 +166,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();
@@ -773,8 +552,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());
@@ -1443,82 +1222,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())
@@ -1564,7 +1267,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?
@@ -1722,7 +1425,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;
@@ -1738,43 +1441,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 checkOMPAssumeAttr(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_omp_assume_attribute_string_unknown_suggested)
- << AssumptionStr << Suggestion;
- else
- S.Diag(Loc, diag::warn_omp_assume_attribute_string_unknown)
- << AssumptionStr;
-}
-
-static void handleOMPAssumeAttr(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;
-
- checkOMPAssumeAttr(S, AttrStrLoc, Str);
-
- D->addAttr(::new (S.Context) OMPAssumeAttr(S.Context, AL, Str));
-}
-
/// Normalize the attribute, __foo__ becomes foo.
/// Returns true if normalization was applied.
static bool normalizeName(StringRef &AttrName) {
@@ -1833,7 +1499,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?
@@ -2141,21 +1807,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();
@@ -2370,17 +2021,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,
@@ -2967,113 +2607,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) {
@@ -3263,27 +2796,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 (!S.checkUInt32Argument(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;
@@ -3854,15 +3366,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)
@@ -3877,8 +3388,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)
@@ -4073,8 +3584,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)
@@ -5034,22 +4544,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>()) {
@@ -5572,94 +5066,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) {
@@ -5803,13 +5209,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";
@@ -5856,9 +5262,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]
@@ -5885,1250 +5291,60 @@ 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) {
- if (!AL.isArgIdent(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
- << AL << 1 << AANT_ArgumentIdentifier;
- 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();
- 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);
- 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;
-}
-
-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;
- 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;
- return;
- }
-
- D->addAttr(::new (S.Context) BuiltinAliasAttr(S.Context, AL, Ident));
-}
-
-static void handleNullableTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (AL.isUsedAsTypeAttr())
- return;
-
- 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;
- }
-
- handleSimpleAttribute<TypeNullableAttr>(S, D, AL);
-}
-
-static void handlePreferredTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!AL.hasParsedType()) {
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
- return;
- }
-
- TypeSourceInfo *ParmTSI = nullptr;
- QualType QT = S.GetTypeFromParser(AL.getTypeArg(), &ParmTSI);
- assert(ParmTSI && "no type source info for attribute argument");
- S.RequireCompleteType(ParmTSI->getTypeLoc().getBeginLoc(), QT,
- diag::err_incomplete_type);
-
- D->addAttr(::new (S.Context) PreferredTypeAttr(S.Context, AL, ParmTSI));
-}
-
-//===----------------------------------------------------------------------===//
-// 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
diff erent 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.ObjC().getNSErrorIdent())
- return true;
-
- // Check for CFError**.
- if (const auto *PT = Pointee->getAs<PointerType>())
- if (const auto *RT = PT->getPointeeType()->getAs<RecordType>())
- if (S.ObjC().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.ObjC().getNSErrorIdent()) {
- AnyErrorParams = true;
- break;
- }
- }
- }
- // Check for CFError *.
- if (const auto *PtrTy = Param->getAs<PointerType>()) {
- if (const auto *RT = PtrTy->getPointeeType()->getAs<RecordType>()) {
- if (S.ObjC().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 (!S.checkUInt32Argument(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.consume_front("getter:"))
- IsGetter = true;
- else if (Name.consume_front("setter:"))
- IsSetter = true;
-
- 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;
-
+static void handleBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!AL.isArgIdent(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIdentifier;
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
+ << AL << 1 << 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;
- }
+ IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident;
+ unsigned BuiltinID = Ident->getBuiltinID();
+ StringRef AliasName = cast<FunctionDecl>(D)->getIdentifier()->getName();
- if (!isa<TypedefNameDecl>(D)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str)
- << AL << AL.isRegularKeywordAttribute() << "typedefs";
+ 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 && !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) SwiftNewTypeAttr(S.Context, AL, Kind));
+ D->addAttr(::new (S.Context) BuiltinAliasAttr(S.Context, AL, Ident));
}
-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;
+static void handleNullableTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (AL.isUsedAsTypeAttr())
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;
+ 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;
}
- 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;
+ handleSimpleAttribute<TypeNullableAttr>(S, D, AL);
+}
- 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;
- }
+static void handlePreferredTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (!AL.hasParsedType()) {
+ S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
+ return;
}
- auto *AsyncAttr =
- ::new (S.Context) SwiftAsyncAttr(S.Context, AL, Kind, Idx);
- D->addAttr(AsyncAttr);
+ TypeSourceInfo *ParmTSI = nullptr;
+ QualType QT = S.GetTypeFromParser(AL.getTypeArg(), &ParmTSI);
+ assert(ParmTSI && "no type source info for attribute argument");
+ S.RequireCompleteType(ParmTSI->getTypeLoc().getBeginLoc(), QT,
+ diag::err_incomplete_type);
- if (auto *ErrorAttr = D->getAttr<SwiftAsyncErrorAttr>())
- checkSwiftAsyncErrorBlock(S, D, ErrorAttr, AsyncAttr);
+ D->addAttr(::new (S.Context) PreferredTypeAttr(S.Context, AL, ParmTSI));
}
//===----------------------------------------------------------------------===//
@@ -7194,246 +5410,20 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
for (unsigned i = 0; i != 8; ++i)
StrRef.substr(19 + 2 * i + (i >= 2 ? 1 : 0), 2)
.getAsInteger(16, Parsed.Part4And5[i]);
- MSGuidDecl *Guid = S.Context.getMSGuidDecl(Parsed);
-
- // FIXME: It'd be nice to also emit a fixit removing uuid(...) (and, if it's
- // the only thing in the [] list, the [] too), and add an insertion of
- // __declspec(uuid(...)). But sadly, neither the SourceLocs of the commas
- // separating attributes nor of the [ and the ] are in the AST.
- // Cf "SourceLocations of attribute list delimiters - [[ ... , ... ]] etc"
- // on cfe-dev.
- if (AL.isMicrosoftAttribute()) // Check for [uuid(...)] spelling.
- S.Diag(AL.getLoc(), diag::warn_atl_uuid_deprecated);
-
- UuidAttr *UA = S.mergeUuidAttr(D, AL, OrigStrRef, Guid);
- if (UA)
- 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 (!S.checkUInt32Argument(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 (!S.checkUInt32Argument(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 (!S.checkUInt32Argument(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.HLSL().mergeNumThreadsAttr(D, AL, X, Y, Z);
- if (NewAttr)
- D->addAttr(NewAttr);
-}
-
-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 handleHLSLPackOffsetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!isa<VarDecl>(D) || !isa<HLSLBufferDecl>(D->getDeclContext())) {
- S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
- << AL << "shader constant in a constant buffer";
- return;
- }
-
- uint32_t SubComponent;
- if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), SubComponent))
- return;
- uint32_t Component;
- if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(1), Component))
- return;
-
- QualType T = cast<VarDecl>(D)->getType().getCanonicalType();
- // Check if T is an array or struct type.
- // TODO: mark matrix type as aggregate type.
- bool IsAggregateTy = (T->isArrayType() || T->isStructureType());
-
- // Check Component is valid for T.
- if (Component) {
- unsigned Size = S.getASTContext().getTypeSize(T);
- if (IsAggregateTy || Size > 128) {
- S.Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
- return;
- } else {
- // Make sure Component + sizeof(T) <= 4.
- if ((Component * 32 + Size) > 128) {
- S.Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
- return;
- }
- QualType EltTy = T;
- if (const auto *VT = T->getAs<VectorType>())
- EltTy = VT->getElementType();
- unsigned Align = S.getASTContext().getTypeAlign(EltTy);
- if (Align > 32 && Component == 1) {
- // NOTE: Component 3 will hit err_hlsl_packoffset_cross_reg_boundary.
- // So we only need to check Component 1 here.
- S.Diag(AL.getLoc(), diag::err_hlsl_packoffset_alignment_mismatch)
- << Align << EltTy;
- return;
- }
- }
- }
-
- D->addAttr(::new (S.Context)
- HLSLPackOffsetAttr(S.Context, AL, SubComponent, Component));
-}
-
-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.HLSL().mergeShaderAttr(D, AL, ShaderType);
- if (NewAttr)
- D->addAttr(NewAttr);
-}
-
-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);
-}
+ MSGuidDecl *Guid = S.Context.getMSGuidDecl(Parsed);
-static void handleHLSLParamModifierAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- HLSLParamModifierAttr *NewAttr = S.HLSL().mergeParamModifierAttr(
- D, AL,
- static_cast<HLSLParamModifierAttr::Spelling>(AL.getSemanticSpelling()));
- if (NewAttr)
- D->addAttr(NewAttr);
+ // FIXME: It'd be nice to also emit a fixit removing uuid(...) (and, if it's
+ // the only thing in the [] list, the [] too), and add an insertion of
+ // __declspec(uuid(...)). But sadly, neither the SourceLocs of the commas
+ // separating attributes nor of the [ and the ] are in the AST.
+ // Cf "SourceLocations of attribute list delimiters - [[ ... , ... ]] etc"
+ // on cfe-dev.
+ if (AL.isMicrosoftAttribute()) // Check for [uuid(...)] spelling.
+ S.Diag(AL.getLoc(), diag::warn_atl_uuid_deprecated);
+
+ UuidAttr *UA = S.mergeUuidAttr(D, AL, OrigStrRef, Guid);
+ if (UA)
+ D->addAttr(UA);
}
static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -7520,284 +5510,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 (!isFuncOrMethodForAttrSubject(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 (!isFuncOrMethodForAttrSubject(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 (!isFuncOrMethodForAttrSubject(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 (!isFuncOrMethodForAttrSubject(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 (!isFuncOrMethodForAttrSubject(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)
@@ -7822,117 +5534,36 @@ BTFDeclTagAttr *Sema::mergeBTFDeclTagAttr(Decl *D, const BTFDeclTagAttr &AL) {
return ::new (Context) BTFDeclTagAttr(Context, AL, AL.getBTFDeclTag());
}
-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 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));
@@ -8230,62 +5861,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;
@@ -8519,45 +6094,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)
@@ -8577,81 +6113,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();
-
- // SemaObjC::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.
@@ -8841,82 +6302,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.
@@ -9039,7 +6424,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);
@@ -9064,10 +6449,10 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
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);
@@ -9085,10 +6470,10 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &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);
@@ -9179,7 +6564,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);
@@ -9265,53 +6650,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;
@@ -9322,7 +6708,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);
@@ -9331,7 +6717,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);
@@ -9376,17 +6762,17 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
handleAttrWithMessage<UnavailableAttr>(S, D, AL);
break;
case ParsedAttr::AT_OMPAssume:
- handleOMPAssumeAttr(S, D, AL);
+ 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);
@@ -9410,16 +6796,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);
@@ -9431,7 +6817,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:
@@ -9464,22 +6850,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);
@@ -9524,25 +6910,25 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
// 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:
- handleHLSLPackOffsetAttr(S, D, AL);
+ 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_HLSLParamModifier:
- handleHLSLParamModifierAttr(S, D, AL);
+ S.HLSL().handleParamModifierAttr(D, AL);
break;
case ParsedAttr::AT_AbiTag:
@@ -9645,28 +7031,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.
@@ -9688,7 +7074,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:
@@ -9700,7 +7086,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:
@@ -9708,7 +7094,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:
@@ -9841,7 +7227,7 @@ 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
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 9e614ae99f37d..0a2face7afe65 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -15,6 +15,7 @@
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Sema.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
@@ -295,6 +296,233 @@ void SemaHLSL::DiagnoseAttrStageMismatch(
<< (AllowedStages.size() != 1) << join(StageStrings, ", ");
}
+void SemaHLSL::handleNumThreadsAttr(Decl *D, const ParsedAttr &AL) {
+ llvm::VersionTuple SMVersion =
+ getASTContext().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 (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), X))
+ return;
+ if (X > 1024) {
+ Diag(AL.getArgAsExpr(0)->getExprLoc(),
+ diag::err_hlsl_numthreads_argument_oor)
+ << 0 << 1024;
+ return;
+ }
+ uint32_t Y;
+ if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Y))
+ return;
+ if (Y > 1024) {
+ Diag(AL.getArgAsExpr(1)->getExprLoc(),
+ diag::err_hlsl_numthreads_argument_oor)
+ << 1 << 1024;
+ return;
+ }
+ uint32_t Z;
+ if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(2), Z))
+ return;
+ if (Z > ZMax) {
+ SemaRef.Diag(AL.getArgAsExpr(2)->getExprLoc(),
+ diag::err_hlsl_numthreads_argument_oor)
+ << 2 << ZMax;
+ return;
+ }
+
+ if (X * Y * Z > ThreadMax) {
+ Diag(AL.getLoc(), diag::err_hlsl_numthreads_invalid) << ThreadMax;
+ return;
+ }
+
+ HLSLNumThreadsAttr *NewAttr = mergeNumThreadsAttr(D, AL, X, Y, Z);
+ if (NewAttr)
+ D->addAttr(NewAttr);
+}
+
+static bool isLegalTypeForHLSLSV_DispatchThreadID(QualType T) {
+ if (!T->hasUnsignedIntegerRepresentation())
+ return false;
+ if (const auto *VT = T->getAs<VectorType>())
+ return VT->getNumElements() <= 3;
+ return true;
+}
+
+void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) {
+ // FIXME: support semantic on field.
+ // See https://github.com/llvm/llvm-project/issues/57889.
+ if (isa<FieldDecl>(D)) {
+ Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
+ << AL << "parameter";
+ return;
+ }
+
+ auto *VD = cast<ValueDecl>(D);
+ if (!isLegalTypeForHLSLSV_DispatchThreadID(VD->getType())) {
+ Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
+ << AL << "uint/uint2/uint3";
+ return;
+ }
+
+ D->addAttr(::new (getASTContext())
+ HLSLSV_DispatchThreadIDAttr(getASTContext(), AL));
+}
+
+void SemaHLSL::handlePackOffsetAttr(Decl *D, const ParsedAttr &AL) {
+ if (!isa<VarDecl>(D) || !isa<HLSLBufferDecl>(D->getDeclContext())) {
+ Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
+ << AL << "shader constant in a constant buffer";
+ return;
+ }
+
+ uint32_t SubComponent;
+ if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), SubComponent))
+ return;
+ uint32_t Component;
+ if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Component))
+ return;
+
+ QualType T = cast<VarDecl>(D)->getType().getCanonicalType();
+ // Check if T is an array or struct type.
+ // TODO: mark matrix type as aggregate type.
+ bool IsAggregateTy = (T->isArrayType() || T->isStructureType());
+
+ // Check Component is valid for T.
+ if (Component) {
+ unsigned Size = getASTContext().getTypeSize(T);
+ if (IsAggregateTy || Size > 128) {
+ Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
+ return;
+ } else {
+ // Make sure Component + sizeof(T) <= 4.
+ if ((Component * 32 + Size) > 128) {
+ Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
+ return;
+ }
+ QualType EltTy = T;
+ if (const auto *VT = T->getAs<VectorType>())
+ EltTy = VT->getElementType();
+ unsigned Align = getASTContext().getTypeAlign(EltTy);
+ if (Align > 32 && Component == 1) {
+ // NOTE: Component 3 will hit err_hlsl_packoffset_cross_reg_boundary.
+ // So we only need to check Component 1 here.
+ Diag(AL.getLoc(), diag::err_hlsl_packoffset_alignment_mismatch)
+ << Align << EltTy;
+ return;
+ }
+ }
+ }
+
+ D->addAttr(::new (getASTContext()) HLSLPackOffsetAttr(
+ getASTContext(), AL, SubComponent, Component));
+}
+
+void SemaHLSL::handleShaderAttr(Decl *D, const ParsedAttr &AL) {
+ StringRef Str;
+ SourceLocation ArgLoc;
+ if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
+ return;
+
+ HLSLShaderAttr::ShaderType ShaderType;
+ if (!HLSLShaderAttr::ConvertStrToShaderType(Str, ShaderType)) {
+ Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
+ << AL << Str << ArgLoc;
+ return;
+ }
+
+ // FIXME: check function match the shader stage.
+
+ HLSLShaderAttr *NewAttr = mergeShaderAttr(D, AL, ShaderType);
+ if (NewAttr)
+ D->addAttr(NewAttr);
+}
+
+void SemaHLSL::handleResourceBindingAttr(Decl *D, const ParsedAttr &AL) {
+ StringRef Space = "space0";
+ StringRef Slot = "";
+
+ if (!AL.isArgIdent(0)) {
+ 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)) {
+ 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:
+ 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)) {
+ Diag(ArgLoc, diag::err_hlsl_unsupported_register_number);
+ return;
+ }
+ }
+
+ if (!Space.starts_with("space")) {
+ Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
+ return;
+ }
+ StringRef SpaceNum = Space.substr(5);
+ unsigned Num = 0;
+ if (SpaceNum.getAsInteger(10, Num)) {
+ 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(getASTContext(), Slot, Space, AL);
+ if (NewAttr)
+ D->addAttr(NewAttr);
+}
+
+void SemaHLSL::handleParamModifierAttr(Decl *D, const ParsedAttr &AL) {
+ HLSLParamModifierAttr *NewAttr = mergeParamModifierAttr(
+ D, AL,
+ static_cast<HLSLParamModifierAttr::Spelling>(AL.getSemanticSpelling()));
+ if (NewAttr)
+ D->addAttr(NewAttr);
+}
+
namespace {
/// This class implements HLSL availability diagnostics for default
diff --git a/clang/lib/Sema/SemaM68k.cpp b/clang/lib/Sema/SemaM68k.cpp
new file mode 100644
index 0000000000000..f091827092f83
--- /dev/null
+++ b/clang/lib/Sema/SemaM68k.cpp
@@ -0,0 +1,56 @@
+//===------ SemaM68k.cpp -------- M68k target-specific routines -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis functions specific to M68k.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/SemaM68k.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/Basic/DiagnosticSema.h"
+#include "clang/Sema/ParsedAttr.h"
+
+namespace clang {
+SemaM68k::SemaM68k(Sema &S) : SemaBase(S) {}
+
+void SemaM68k::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
+ if (!AL.checkExactlyNumArgs(SemaRef, 1))
+ return;
+
+ if (!AL.isArgExpr(0)) {
+ 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(getASTContext());
+ if (!MaybeNumParams) {
+ Diag(AL.getLoc(), diag::err_attribute_argument_type)
+ << AL << AANT_ArgumentIntegerConstant
+ << NumParamsExpr->getSourceRange();
+ return;
+ }
+
+ unsigned Num = MaybeNumParams->getLimitedValue(255);
+ if ((Num & 1) || Num > 30) {
+ Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << AL << (int)MaybeNumParams->getSExtValue()
+ << NumParamsExpr->getSourceRange();
+ return;
+ }
+
+ D->addAttr(::new (getASTContext())
+ M68kInterruptAttr(getASTContext(), AL, Num));
+ D->addAttr(UsedAttr::CreateImplicit(getASTContext()));
+}
+} // namespace clang
diff --git a/clang/lib/Sema/SemaMIPS.cpp b/clang/lib/Sema/SemaMIPS.cpp
index df5328fbf6640..269d927903c5d 100644
--- a/clang/lib/Sema/SemaMIPS.cpp
+++ b/clang/lib/Sema/SemaMIPS.cpp
@@ -13,6 +13,8 @@
#include "clang/Sema/SemaMIPS.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/TargetBuiltins.h"
+#include "clang/Sema/Attr.h"
+#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Sema.h"
namespace clang {
@@ -237,4 +239,62 @@ bool SemaMIPS::CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) {
SemaRef.BuiltinConstantArgMultiple(TheCall, i, m);
}
+void SemaMIPS::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
+ // Only one optional argument permitted.
+ if (AL.getNumArgs() > 1) {
+ Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1;
+ return;
+ }
+
+ StringRef Str;
+ SourceLocation ArgLoc;
+
+ if (AL.getNumArgs() == 0)
+ Str = "";
+ else if (!SemaRef.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 (!isFuncOrMethodForAttrSubject(D)) {
+ Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
+ << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
+ Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
+ << /*MIPS*/ 0 << 0;
+ return;
+ }
+
+ if (!getFunctionOrMethodResultType(D)->isVoidType()) {
+ 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>(*this, D, AL))
+ return;
+
+ MipsInterruptAttr::InterruptType Kind;
+ if (!MipsInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
+ Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
+ << AL << "'" + std::string(Str) + "'";
+ return;
+ }
+
+ D->addAttr(::new (getASTContext())
+ MipsInterruptAttr(getASTContext(), AL, Kind));
+}
+
} // namespace clang
diff --git a/clang/lib/Sema/SemaMSP430.cpp b/clang/lib/Sema/SemaMSP430.cpp
new file mode 100644
index 0000000000000..4038a1ff61d63
--- /dev/null
+++ b/clang/lib/Sema/SemaMSP430.cpp
@@ -0,0 +1,78 @@
+//===------ SemaMSP430.cpp ----- MSP430 target-specific routines ----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis functions specific to NVPTX.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/SemaMSP430.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/Basic/DiagnosticSema.h"
+#include "clang/Sema/Attr.h"
+#include "clang/Sema/ParsedAttr.h"
+
+namespace clang {
+
+SemaMSP430::SemaMSP430(Sema &S) : SemaBase(S) {}
+
+void SemaMSP430::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
+ // MSP430 'interrupt' attribute is applied to
+ // a function with no parameters and void return type.
+ if (!isFuncOrMethodForAttrSubject(D)) {
+ Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
+ << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
+ Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
+ << /*MSP430*/ 1 << 0;
+ return;
+ }
+
+ if (!getFunctionOrMethodResultType(D)->isVoidType()) {
+ Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
+ << /*MSP430*/ 1 << 1;
+ return;
+ }
+
+ // The attribute takes one integer argument.
+ if (!AL.checkExactlyNumArgs(SemaRef, 1))
+ return;
+
+ if (!AL.isArgExpr(0)) {
+ 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(getASTContext()))) {
+ 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) {
+ Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << AL << (int)NumParams->getSExtValue()
+ << NumParamsExpr->getSourceRange();
+ return;
+ }
+
+ D->addAttr(::new (getASTContext())
+ MSP430InterruptAttr(getASTContext(), AL, Num));
+ D->addAttr(UsedAttr::CreateImplicit(getASTContext()));
+}
+
+} // namespace clang
diff --git a/clang/lib/Sema/SemaObjC.cpp b/clang/lib/Sema/SemaObjC.cpp
index 1e6cc21a48704..d396258cfc7d1 100644
--- a/clang/lib/Sema/SemaObjC.cpp
+++ b/clang/lib/Sema/SemaObjC.cpp
@@ -11,10 +11,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaObjC.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Attr.h"
+#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/TemplateDeduction.h"
@@ -1483,4 +1486,773 @@ bool SemaObjC::isCFError(RecordDecl *RD) {
return false;
}
+bool SemaObjC::isNSStringType(QualType T, bool AllowNSAttributedString) {
+ 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 == &getASTContext().Idents.get("NSAttributedString"))
+ return true;
+ // FIXME: Should we walk the chain of classes?
+ return ClsName == &getASTContext().Idents.get("NSString") ||
+ ClsName == &getASTContext().Idents.get("NSMutableString");
+}
+
+bool SemaObjC::isCFStringType(QualType T) {
+ 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() == &getASTContext().Idents.get("__CFString");
+}
+
+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;
+}
+
+void SemaObjC::handleIBOutlet(Decl *D, const ParsedAttr &AL) {
+ if (!checkIBOutletCommon(SemaRef, D, AL))
+ return;
+
+ D->addAttr(::new (getASTContext()) IBOutletAttr(getASTContext(), AL));
+}
+
+void SemaObjC::handleIBOutletCollection(Decl *D, const ParsedAttr &AL) {
+
+ ASTContext &Context = getASTContext();
+ // The iboutletcollection attribute can have zero or one arguments.
+ if (AL.getNumArgs() > 1) {
+ Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
+ return;
+ }
+
+ if (!checkIBOutletCommon(SemaRef, D, AL))
+ return;
+
+ ParsedType PT;
+
+ if (AL.hasParsedType())
+ PT = AL.getTypeArg();
+ else {
+ PT = SemaRef.getTypeName(
+ Context.Idents.get("NSObject"), AL.getLoc(),
+ SemaRef.getScopeForContext(D->getDeclContext()->getParent()));
+ if (!PT) {
+ Diag(AL.getLoc(), diag::err_iboutletcollection_type) << "NSObject";
+ return;
+ }
+ }
+
+ TypeSourceInfo *QTLoc = nullptr;
+ QualType QT = SemaRef.GetTypeFromParser(PT, &QTLoc);
+ if (!QTLoc)
+ QTLoc = 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()) {
+ Diag(AL.getLoc(), QT->isBuiltinType()
+ ? diag::err_iboutletcollection_builtintype
+ : diag::err_iboutletcollection_type)
+ << QT;
+ return;
+ }
+
+ D->addAttr(::new (Context) IBOutletCollectionAttr(Context, AL, QTLoc));
+}
+
+void SemaObjC::handleSuppresProtocolAttr(Decl *D, const ParsedAttr &AL) {
+ if (!cast<ObjCProtocolDecl>(D)->isThisDeclarationADefinition()) {
+ Diag(AL.getLoc(), diag::err_objc_attr_protocol_requires_definition)
+ << AL << AL.getRange();
+ return;
+ }
+
+ D->addAttr(::new (getASTContext())
+ ObjCExplicitProtocolImplAttr(getASTContext(), AL));
+}
+
+void SemaObjC::handleDirectAttr(Decl *D, const ParsedAttr &AL) {
+ // objc_direct cannot be set on methods declared in the context of a protocol
+ if (isa<ObjCProtocolDecl>(D->getDeclContext())) {
+ Diag(AL.getLoc(), diag::err_objc_direct_on_protocol) << false;
+ return;
+ }
+
+ if (getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
+ handleSimpleAttribute<ObjCDirectAttr>(*this, D, AL);
+ } else {
+ Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL;
+ }
+}
+
+void SemaObjC::handleDirectMembersAttr(Decl *D, const ParsedAttr &AL) {
+ if (getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
+ handleSimpleAttribute<ObjCDirectMembersAttr>(*this, D, AL);
+ } else {
+ Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL;
+ }
+}
+
+void SemaObjC::handleMethodFamilyAttr(Decl *D, const ParsedAttr &AL) {
+ const auto *M = cast<ObjCMethodDecl>(D);
+ if (!AL.isArgIdent(0)) {
+ 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)) {
+ Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL << IL->Ident;
+ return;
+ }
+
+ if (F == ObjCMethodFamilyAttr::OMF_init &&
+ !M->getReturnType()->isObjCObjectPointerType()) {
+ Diag(M->getLocation(), diag::err_init_method_bad_return_type)
+ << M->getReturnType();
+ // Ignore the attribute.
+ return;
+ }
+
+ D->addAttr(new (getASTContext())
+ ObjCMethodFamilyAttr(getASTContext(), AL, F));
+}
+
+void SemaObjC::handleNSObject(Decl *D, const ParsedAttr &AL) {
+ if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
+ QualType T = TD->getUnderlyingType();
+ if (!T->isCARCBridgableType()) {
+ Diag(TD->getLocation(), diag::err_nsobject_attribute);
+ return;
+ }
+ } else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) {
+ QualType T = PD->getType();
+ if (!T->isCARCBridgableType()) {
+ 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.
+ Diag(D->getLocation(), diag::warn_nsobject_attribute);
+ }
+ D->addAttr(::new (getASTContext()) ObjCNSObjectAttr(getASTContext(), AL));
+}
+
+void SemaObjC::handleIndependentClass(Decl *D, const ParsedAttr &AL) {
+ if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
+ QualType T = TD->getUnderlyingType();
+ if (!T->isObjCObjectPointerType()) {
+ Diag(TD->getLocation(), diag::warn_ptr_independentclass_attribute);
+ return;
+ }
+ } else {
+ Diag(D->getLocation(), diag::warn_independentclass_attribute);
+ return;
+ }
+ D->addAttr(::new (getASTContext())
+ ObjCIndependentClassAttr(getASTContext(), AL));
+}
+
+void SemaObjC::handleBlocksAttr(Decl *D, const ParsedAttr &AL) {
+ if (!AL.isArgIdent(0)) {
+ 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)) {
+ Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II;
+ return;
+ }
+
+ D->addAttr(::new (getASTContext()) BlocksAttr(getASTContext(), AL, type));
+}
+
+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 SemaObjC::AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI,
+ Sema::RetainOwnershipKind K,
+ bool IsTemplateInstantiation) {
+ ValueDecl *VD = cast<ValueDecl>(D);
+ switch (K) {
+ case Sema::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 Sema::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 Sema::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;
+ }
+}
+
+Sema::RetainOwnershipKind
+SemaObjC::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 SemaObjC::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.
+bool SemaObjC::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);
+}
+
+void SemaObjC::handleXReturnsXRetainedAttr(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 (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()) {
+ 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;
+ }
+ 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)) {
+ 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;
+ 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>(*this, D, AL);
+ return;
+ case ParsedAttr::AT_CFReturnsNotRetained:
+ handleSimpleAttribute<CFReturnsNotRetainedAttr>(*this, D, AL);
+ return;
+ case ParsedAttr::AT_NSReturnsNotRetained:
+ handleSimpleAttribute<NSReturnsNotRetainedAttr>(*this, D, AL);
+ return;
+ case ParsedAttr::AT_CFReturnsRetained:
+ handleSimpleAttribute<CFReturnsRetainedAttr>(*this, D, AL);
+ return;
+ case ParsedAttr::AT_NSReturnsRetained:
+ handleSimpleAttribute<NSReturnsRetainedAttr>(*this, D, AL);
+ return;
+ case ParsedAttr::AT_OSReturnsRetained:
+ handleSimpleAttribute<OSReturnsRetainedAttr>(*this, D, AL);
+ return;
+ case ParsedAttr::AT_OSReturnsNotRetained:
+ handleSimpleAttribute<OSReturnsNotRetainedAttr>(*this, D, AL);
+ return;
+ };
+}
+
+void SemaObjC::handleReturnsInnerPointerAttr(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())) {
+ 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 (getASTContext())
+ ObjCReturnsInnerPointerAttr(getASTContext(), Attrs));
+}
+
+void SemaObjC::handleRequiresSuperAttr(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)) {
+ Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol)
+ << Attrs << 0;
+ Diag(PDecl->getLocation(), diag::note_protocol_decl);
+ return;
+ }
+ if (Method->getMethodFamily() == OMF_dealloc) {
+ Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol)
+ << Attrs << 1;
+ return;
+ }
+
+ D->addAttr(::new (getASTContext())
+ ObjCRequiresSuperAttr(getASTContext(), Attrs));
+}
+
+void SemaObjC::handleNSErrorDomain(Decl *D, const ParsedAttr &Attr) {
+ if (!isa<TagDecl>(D)) {
+ 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();
+
+ Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0;
+ return;
+ }
+
+ // Verify that the identifier is a valid decl in the C decl namespace.
+ LookupResult Result(SemaRef, DeclarationName(IdentLoc->Ident),
+ SourceLocation(),
+ Sema::LookupNameKind::LookupOrdinaryName);
+ if (!SemaRef.LookupName(Result, SemaRef.TUScope) ||
+ !Result.getAsSingle<VarDecl>()) {
+ Diag(IdentLoc->Loc, diag::err_nserrordomain_invalid_decl)
+ << 1 << IdentLoc->Ident;
+ return;
+ }
+
+ D->addAttr(::new (getASTContext())
+ NSErrorDomainAttr(getASTContext(), Attr, IdentLoc->Ident));
+}
+
+void SemaObjC::handleBridgeAttr(Decl *D, const ParsedAttr &AL) {
+ IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr;
+
+ if (!Parm) {
+ 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")) {
+ Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_id) << AL;
+ return;
+ }
+
+ // Only allow 'cv void *'.
+ QualType T = TD->getUnderlyingType();
+ if (!T->isVoidPointerType()) {
+ Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_void_pointer);
+ return;
+ }
+ }
+
+ D->addAttr(::new (getASTContext())
+ ObjCBridgeAttr(getASTContext(), AL, Parm->Ident));
+}
+
+void SemaObjC::handleBridgeMutableAttr(Decl *D, const ParsedAttr &AL) {
+ IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr;
+
+ if (!Parm) {
+ Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0;
+ return;
+ }
+
+ D->addAttr(::new (getASTContext())
+ ObjCBridgeMutableAttr(getASTContext(), AL, Parm->Ident));
+}
+
+void SemaObjC::handleBridgeRelatedAttr(Decl *D, const ParsedAttr &AL) {
+ IdentifierInfo *RelatedClass =
+ AL.isArgIdent(0) ? AL.getArgAsIdent(0)->Ident : nullptr;
+ if (!RelatedClass) {
+ 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 (getASTContext()) ObjCBridgeRelatedAttr(
+ getASTContext(), AL, RelatedClass, ClassMethod, InstanceMethod));
+}
+
+void SemaObjC::handleDesignatedInitializer(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())) {
+ 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 (getASTContext())
+ ObjCDesignatedInitializerAttr(getASTContext(), AL));
+}
+
+void SemaObjC::handleRuntimeName(Decl *D, const ParsedAttr &AL) {
+ StringRef MetaDataName;
+ if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, MetaDataName))
+ return;
+ D->addAttr(::new (getASTContext())
+ ObjCRuntimeNameAttr(getASTContext(), 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;
+void SemaObjC::handleBoxable(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 (getASTContext()) ObjCBoxableAttr(getASTContext(), AL);
+ RD->addAttr(BoxableAttr);
+ if (notify) {
+ // we need to notify ASTReader/ASTWriter about
+ // modification of existing declaration
+ if (ASTMutationListener *L = SemaRef.getASTMutationListener())
+ L->AddedAttributeToRecord(BoxableAttr, RD);
+ }
+ }
+}
+
+void SemaObjC::handleOwnershipAttr(Decl *D, const ParsedAttr &AL) {
+ if (hasDeclarator(D))
+ return;
+
+ Diag(D->getBeginLoc(), diag::err_attribute_wrong_decl_type)
+ << AL.getRange() << AL << AL.isRegularKeywordAttribute()
+ << ExpectedVariable;
+}
+
+void SemaObjC::handlePreciseLifetimeAttr(Decl *D, const ParsedAttr &AL) {
+ const auto *VD = cast<ValueDecl>(D);
+ QualType QT = VD->getType();
+
+ if (!QT->isDependentType() && !QT->isObjCLifetimeType()) {
+ 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:
+ Diag(AL.getLoc(), diag::warn_objc_precise_lifetime_meaningless)
+ << (Lifetime == Qualifiers::OCL_Autoreleasing);
+ break;
+ }
+
+ D->addAttr(::new (getASTContext())
+ ObjCPreciseLifetimeAttr(getASTContext(), 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();
+
+ // SemaObjC::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;
+}
+
+void SemaObjC::handleExternallyRetainedAttr(Decl *D, const ParsedAttr &AL) {
+ if (auto *VD = dyn_cast<VarDecl>(D)) {
+ assert(!isa<ParmVarDecl>(VD) && "should be diagnosed automatically");
+ if (!VD->hasLocalStorage()) {
+ Diag(D->getBeginLoc(), diag::warn_ignored_objc_externally_retained) << 0;
+ return;
+ }
+
+ if (!tryMakeVariablePseudoStrong(SemaRef, VD, /*DiagnoseFailure=*/true))
+ return;
+
+ handleSimpleAttribute<ObjCExternallyRetainedAttr>(*this, 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(SemaRef, PVD, /*DiagnoseFailure=*/false);
+ }
+ handleSimpleAttribute<ObjCExternallyRetainedAttr>(*this, D, AL);
+}
+
} // namespace clang
diff --git a/clang/lib/Sema/SemaOpenCL.cpp b/clang/lib/Sema/SemaOpenCL.cpp
new file mode 100644
index 0000000000000..b3b495a15e02c
--- /dev/null
+++ b/clang/lib/Sema/SemaOpenCL.cpp
@@ -0,0 +1,99 @@
+//===--- SemaOpenCL.cpp --- Semantic Analysis for OpenCL constructs -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file implements semantic analysis for OpenCL.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/SemaOpenCL.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/Basic/DiagnosticSema.h"
+#include "clang/Sema/ParsedAttr.h"
+#include "clang/Sema/Sema.h"
+
+namespace clang {
+SemaOpenCL::SemaOpenCL(Sema &S) : SemaBase(S) {}
+
+void SemaOpenCL::handleNoSVMAttr(Decl *D, const ParsedAttr &AL) {
+ if (getLangOpts().getOpenCLCompatibleVersion() < 200)
+ Diag(AL.getLoc(), diag::err_attribute_requires_opencl_version)
+ << AL << "2.0" << 1;
+ else
+ Diag(AL.getLoc(), diag::warn_opencl_attr_deprecated_ignored)
+ << AL << getLangOpts().getOpenCLVersionString();
+}
+
+void SemaOpenCL::handleAccessAttr(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()) {
+ Diag(AL.getLoc(), diag::warn_duplicate_declspec)
+ << AL.getAttrName()->getName() << AL.getRange();
+ } else {
+ 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 =
+ (getLangOpts().getOpenCLCompatibleVersion() < 200) ||
+ (getLangOpts().getOpenCLCompatibleVersion() == 300 &&
+ !SemaRef.getOpenCLOptions().isSupported(
+ "__opencl_c_read_write_images", getLangOpts()));
+ if (ReadWriteImagesUnsupported || DeclTy->isPipeType()) {
+ Diag(AL.getLoc(), diag::err_opencl_invalid_read_write)
+ << AL << PDecl->getType() << DeclTy->isImageType();
+ D->setInvalidDecl(true);
+ return;
+ }
+ }
+ }
+
+ D->addAttr(::new (getASTContext()) OpenCLAccessAttr(getASTContext(), AL));
+}
+
+void SemaOpenCL::handleSubGroupSize(Decl *D, const ParsedAttr &AL) {
+ uint32_t SGSize;
+ const Expr *E = AL.getArgAsExpr(0);
+ if (!SemaRef.checkUInt32Argument(AL, E, SGSize))
+ return;
+ if (SGSize == 0) {
+ Diag(AL.getLoc(), diag::err_attribute_argument_is_zero)
+ << AL << E->getSourceRange();
+ return;
+ }
+
+ OpenCLIntelReqdSubGroupSizeAttr *Existing =
+ D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>();
+ if (Existing && Existing->getSubGroupSize() != SGSize)
+ Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
+
+ D->addAttr(::new (getASTContext())
+ OpenCLIntelReqdSubGroupSizeAttr(getASTContext(), AL, SGSize));
+}
+
+} // namespace clang
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 99528c2a4f1f4..6e6815328e913 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -43,6 +43,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Frontend/OpenMP/OMPAssume.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include "llvm/IR/Assumptions.h"
#include <optional>
#include <set>
@@ -25372,5 +25373,42 @@ ExprResult SemaOpenMP::ActOnOMPIteratorExpr(Scope *S,
LLoc, RLoc, ID, Helpers);
}
+/// Check if \p AssumptionStr is a known assumption and warn if not.
+static void checkOMPAssumeAttr(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_omp_assume_attribute_string_unknown_suggested)
+ << AssumptionStr << Suggestion;
+ else
+ S.Diag(Loc, diag::warn_omp_assume_attribute_string_unknown)
+ << AssumptionStr;
+}
+
+void SemaOpenMP::handleOMPAssumeAttr(Decl *D, const ParsedAttr &AL) {
+ // Handle the case where the attribute has a text message.
+ StringRef Str;
+ SourceLocation AttrStrLoc;
+ if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &AttrStrLoc))
+ return;
+
+ checkOMPAssumeAttr(SemaRef, AttrStrLoc, Str);
+
+ D->addAttr(::new (getASTContext()) OMPAssumeAttr(getASTContext(), AL, Str));
+}
+
SemaOpenMP::SemaOpenMP(Sema &S)
: SemaBase(S), VarDataSharingAttributesStack(nullptr) {}
diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp
index ea6e3f75490bc..fd4fc15c1fd79 100644
--- a/clang/lib/Sema/SemaRISCV.cpp
+++ b/clang/lib/Sema/SemaRISCV.cpp
@@ -17,8 +17,10 @@
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Attr.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/RISCVIntrinsicManager.h"
#include "clang/Sema/Sema.h"
#include "clang/Support/RISCVVIntrinsicUtils.h"
@@ -1422,6 +1424,69 @@ bool SemaRISCV::isValidRVVBitcast(QualType srcTy, QualType destTy) {
ValidScalableConversion(destTy, srcTy);
}
+void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
+ // Warn about repeated attributes.
+ if (const auto *A = D->getAttr<RISCVInterruptAttr>()) {
+ Diag(AL.getRange().getBegin(),
+ diag::warn_riscv_repeated_interrupt_attribute);
+ Diag(A->getLocation(), diag::note_riscv_repeated_interrupt_attribute);
+ return;
+ }
+
+ // Check the attribute argument. Argument is optional.
+ if (!AL.checkAtMostNumArgs(SemaRef, 1))
+ return;
+
+ StringRef Str;
+ SourceLocation ArgLoc;
+
+ // 'machine'is the default interrupt mode.
+ if (AL.getNumArgs() == 0)
+ Str = "machine";
+ else if (!SemaRef.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) {
+ Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
+ << AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
+ return;
+ }
+
+ if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
+ Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
+ << /*RISC-V*/ 2 << 0;
+ return;
+ }
+
+ if (!getFunctionOrMethodResultType(D)->isVoidType()) {
+ Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
+ << /*RISC-V*/ 2 << 1;
+ return;
+ }
+
+ RISCVInterruptAttr::InterruptType Kind;
+ if (!RISCVInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
+ Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
+ << AL << Str << ArgLoc;
+ return;
+ }
+
+ D->addAttr(::new (getASTContext())
+ RISCVInterruptAttr(getASTContext(), AL, Kind));
+}
+
+bool SemaRISCV::isAliasValid(unsigned BuiltinID, StringRef AliasName) {
+ return BuiltinID >= RISCV::FirstRVVBuiltin &&
+ BuiltinID <= RISCV::LastRVVBuiltin;
+}
+
SemaRISCV::SemaRISCV(Sema &S) : SemaBase(S) {}
} // namespace clang
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 18f6d8f030473..2b55c598d55c0 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -10,6 +10,8 @@
#include "clang/Sema/SemaSYCL.h"
#include "clang/AST/Mangle.h"
+#include "clang/Sema/Attr.h"
+#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
@@ -156,3 +158,42 @@ ExprResult SemaSYCL::ActOnUniqueStableNameExpr(SourceLocation OpLoc,
return BuildUniqueStableNameExpr(OpLoc, LParen, RParen, TSI);
}
+
+void SemaSYCL::handleKernelAttr(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) {
+ 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)) {
+ Diag(FT->getLocation(),
+ diag::warn_sycl_kernel_invalid_template_param_type);
+ return;
+ }
+ }
+
+ // Function must have at least one argument.
+ if (getFunctionOrMethodNumParams(D) != 1) {
+ Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_function_params);
+ return;
+ }
+
+ // Function must return void.
+ QualType RetTy = getFunctionOrMethodResultType(D);
+ if (!RetTy->isVoidType()) {
+ Diag(FT->getLocation(), diag::warn_sycl_kernel_return_type);
+ return;
+ }
+
+ handleSimpleAttribute<SYCLKernelAttr>(*this, D, AL);
+}
diff --git a/clang/lib/Sema/SemaSwift.cpp b/clang/lib/Sema/SemaSwift.cpp
new file mode 100644
index 0000000000000..bf56ae8ac76d5
--- /dev/null
+++ b/clang/lib/Sema/SemaSwift.cpp
@@ -0,0 +1,765 @@
+//===------ SemaSwift.cpp ------ Swift language-specific routines ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis functions specific to Swift.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/SemaSwift.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/Basic/AttributeCommonInfo.h"
+#include "clang/Basic/DiagnosticSema.h"
+#include "clang/Basic/Specifiers.h"
+#include "clang/Sema/Attr.h"
+#include "clang/Sema/ParsedAttr.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaObjC.h"
+
+namespace clang {
+SemaSwift::SemaSwift(Sema &S) : SemaBase(S) {}
+
+SwiftNameAttr *SemaSwift::mergeNameAttr(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 (getASTContext()) SwiftNameAttr(getASTContext(), SNA, Name);
+}
+
+/// 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 SemaSwift::handleAttrAttr(Decl *D, const ParsedAttr &AL) {
+ // Make sure that there is a string literal as the annotation's single
+ // argument.
+ StringRef Str;
+ if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str))
+ return;
+
+ D->addAttr(::new (getASTContext()) SwiftAttrAttr(getASTContext(), AL, Str));
+}
+
+void SemaSwift::handleBridge(Decl *D, const ParsedAttr &AL) {
+ // Make sure that there is a string literal as the annotation's single
+ // argument.
+ StringRef BT;
+ if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, BT))
+ return;
+
+ // Warn about duplicate attributes if they have
diff erent arguments, but drop
+ // any duplicate attributes regardless.
+ if (const auto *Other = D->getAttr<SwiftBridgeAttr>()) {
+ if (Other->getSwiftType() != BT)
+ Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
+ return;
+ }
+
+ D->addAttr(::new (getASTContext()) SwiftBridgeAttr(getASTContext(), 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.ObjC().getNSErrorIdent())
+ return true;
+
+ // Check for CFError**.
+ if (const auto *PT = Pointee->getAs<PointerType>())
+ if (const auto *RT = PT->getPointeeType()->getAs<RecordType>())
+ if (S.ObjC().isCFError(RT->getDecl()))
+ return true;
+
+ return false;
+}
+
+void SemaSwift::handleError(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)) {
+ 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(SemaRef, D, AL))
+ return;
+ break;
+
+ case SwiftErrorAttr::NullResult:
+ if (!hasErrorParameter(SemaRef, D, AL) || !hasPointerResult(SemaRef, D, AL))
+ return;
+ break;
+
+ case SwiftErrorAttr::NonZeroResult:
+ case SwiftErrorAttr::ZeroResult:
+ if (!hasErrorParameter(SemaRef, D, AL) || !hasIntegerResult(SemaRef, D, AL))
+ return;
+ break;
+ }
+
+ D->addAttr(::new (getASTContext())
+ SwiftErrorAttr(getASTContext(), 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.ObjC().getNSErrorIdent()) {
+ AnyErrorParams = true;
+ break;
+ }
+ }
+ }
+ // Check for CFError *.
+ if (const auto *PtrTy = Param->getAs<PointerType>()) {
+ if (const auto *RT = PtrTy->getPointeeType()->getAs<RecordType>()) {
+ if (S.ObjC().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;
+ }
+}
+
+void SemaSwift::handleAsyncError(Decl *D, const ParsedAttr &AL) {
+ IdentifierLoc *IDLoc = AL.getArgAsIdent(0);
+ SwiftAsyncErrorAttr::ConventionKind ConvKind;
+ if (!SwiftAsyncErrorAttr::ConvertStrToConventionKind(IDLoc->Ident->getName(),
+ ConvKind)) {
+ 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(SemaRef, 2))
+ return;
+
+ Expr *IdxExpr = AL.getArgAsExpr(1);
+ if (!SemaRef.checkUInt32Argument(AL, IdxExpr, ParamIdx))
+ return;
+ break;
+ }
+ case SwiftAsyncErrorAttr::NonNullError:
+ case SwiftAsyncErrorAttr::None: {
+ if (!AL.checkExactlyNumArgs(SemaRef, 1))
+ return;
+ break;
+ }
+ }
+
+ auto *ErrorAttr = ::new (getASTContext())
+ SwiftAsyncErrorAttr(getASTContext(), AL, ConvKind, ParamIdx);
+ D->addAttr(ErrorAttr);
+
+ if (auto *AsyncAttr = D->getAttr<SwiftAsyncAttr>())
+ checkSwiftAsyncErrorBlock(SemaRef, 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.consume_front("getter:"))
+ IsGetter = true;
+ else if (Name.consume_front("setter:"))
+ IsSetter = true;
+
+ 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 SemaSwift::DiagnoseName(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(SemaRef, 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;
+}
+
+void SemaSwift::handleName(Decl *D, const ParsedAttr &AL) {
+ StringRef Name;
+ SourceLocation Loc;
+ if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc))
+ return;
+
+ if (!DiagnoseName(D, Name, Loc, AL, /*IsAsync=*/false))
+ return;
+
+ D->addAttr(::new (getASTContext()) SwiftNameAttr(getASTContext(), AL, Name));
+}
+
+void SemaSwift::handleAsyncName(Decl *D, const ParsedAttr &AL) {
+ StringRef Name;
+ SourceLocation Loc;
+ if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc))
+ return;
+
+ if (!DiagnoseName(D, Name, Loc, AL, /*IsAsync=*/true))
+ return;
+
+ D->addAttr(::new (getASTContext())
+ SwiftAsyncNameAttr(getASTContext(), AL, Name));
+}
+
+void SemaSwift::handleNewType(Decl *D, const ParsedAttr &AL) {
+ // Make sure that there is an identifier as the annotation's single argument.
+ if (!AL.checkExactlyNumArgs(SemaRef, 1))
+ return;
+
+ if (!AL.isArgIdent(0)) {
+ 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)) {
+ Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II;
+ return;
+ }
+
+ if (!isa<TypedefNameDecl>(D)) {
+ Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str)
+ << AL << AL.isRegularKeywordAttribute() << "typedefs";
+ return;
+ }
+
+ D->addAttr(::new (getASTContext())
+ SwiftNewTypeAttr(getASTContext(), AL, Kind));
+}
+
+void SemaSwift::handleAsyncAttr(Decl *D, const ParsedAttr &AL) {
+ if (!AL.isArgIdent(0)) {
+ 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)) {
+ 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(SemaRef, 1))
+ return;
+ } else {
+ // Non-none swift_async requires a completion handler index argument.
+ if (!AL.checkExactlyNumArgs(SemaRef, 2))
+ return;
+
+ Expr *HandlerIdx = AL.getArgAsExpr(1);
+ if (!SemaRef.checkFunctionOrMethodParameterIndex(D, AL, 2, HandlerIdx, Idx))
+ return;
+
+ const ParmVarDecl *CompletionBlock =
+ getFunctionOrMethodParam(D, Idx.getASTIndex());
+ QualType CompletionBlockType = CompletionBlock->getType();
+ if (!CompletionBlockType->isBlockPointerType()) {
+ 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()) {
+ Diag(CompletionBlock->getLocation(), diag::err_swift_async_bad_block_type)
+ << CompletionBlock->getType();
+ return;
+ }
+ }
+
+ auto *AsyncAttr =
+ ::new (getASTContext()) SwiftAsyncAttr(getASTContext(), AL, Kind, Idx);
+ D->addAttr(AsyncAttr);
+
+ if (auto *ErrorAttr = D->getAttr<SwiftAsyncErrorAttr>())
+ checkSwiftAsyncErrorBlock(SemaRef, D, ErrorAttr, AsyncAttr);
+}
+
+void SemaSwift::AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI,
+ ParameterABI abi) {
+ ASTContext &Context = getASTContext();
+ 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");
+}
+
+} // namespace clang
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 4c8eaf2d4ebf6..0681520764d9a 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -31,6 +31,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaObjC.h"
#include "clang/Sema/SemaOpenMP.h"
+#include "clang/Sema/SemaSwift.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateInstCallback.h"
#include "llvm/Support/TimeProfiler.h"
@@ -840,14 +841,15 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
}
if (const auto *ABIAttr = dyn_cast<ParameterABIAttr>(TmplAttr)) {
- AddParameterABIAttr(New, *ABIAttr, ABIAttr->getABI());
+ Swift().AddParameterABIAttr(New, *ABIAttr, ABIAttr->getABI());
continue;
}
if (isa<NSConsumedAttr>(TmplAttr) || isa<OSConsumedAttr>(TmplAttr) ||
isa<CFConsumedAttr>(TmplAttr)) {
- AddXConsumedAttr(New, *TmplAttr, attrToRetainOwnershipKind(TmplAttr),
- /*template instantiation=*/true);
+ ObjC().AddXConsumedAttr(New, *TmplAttr,
+ attrToRetainOwnershipKind(TmplAttr),
+ /*template instantiation=*/true);
continue;
}
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 7cec82c701028..441fdcca0758f 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -2704,7 +2704,7 @@ QualType Sema::BuildFunctionType(QualType T,
if (EPI.ExtInfo.getProducesResult()) {
// This is just a warning, so we can't fail to build if we see it.
- checkNSReturnsRetainedReturnType(Loc, T);
+ ObjC().checkNSReturnsRetainedReturnType(Loc, T);
}
if (Invalid)
@@ -7639,8 +7639,8 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
return false;
// Check whether the return type is reasonable.
- if (S.checkNSReturnsRetainedReturnType(attr.getLoc(),
- unwrapped.get()->getReturnType()))
+ if (S.ObjC().checkNSReturnsRetainedReturnType(
+ attr.getLoc(), unwrapped.get()->getReturnType()))
return true;
// Only actually change the underlying type in ARC builds.
diff --git a/clang/lib/Sema/SemaX86.cpp b/clang/lib/Sema/SemaX86.cpp
index ffac1afc5d782..be26454ce909d 100644
--- a/clang/lib/Sema/SemaX86.cpp
+++ b/clang/lib/Sema/SemaX86.cpp
@@ -13,6 +13,8 @@
#include "clang/Sema/SemaX86.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/TargetBuiltins.h"
+#include "clang/Sema/Attr.h"
+#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Sema.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/TargetParser/Triple.h"
@@ -875,4 +877,96 @@ bool SemaX86::CheckBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
/*RangeIsError*/ false);
}
+void SemaX86::handleAnyInterruptAttr(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.
+ ASTContext &Context = getASTContext();
+
+ if (!isFuncOrMethodForAttrSubject(D) || !hasFunctionProto(D) ||
+ isInstanceMethod(D) ||
+ CXXMethodDecl::isStaticOverloadedOperator(
+ cast<NamedDecl>(D)->getDeclName().getCXXOverloadedOperator())) {
+ 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()) {
+ Diag(getFunctionOrMethodResultSourceRange(D).getBegin(),
+ diag::err_anyx86_interrupt_attribute)
+ << (SemaRef.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) {
+ Diag(D->getBeginLoc(), diag::err_anyx86_interrupt_attribute)
+ << (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
+ ? 0
+ : 1)
+ << 1;
+ return;
+ }
+ // The first argument must be a pointer.
+ if (!getFunctionOrMethodParamType(D, 0)->isPointerType()) {
+ Diag(getFunctionOrMethodParamRange(D, 0).getBegin(),
+ diag::err_anyx86_interrupt_attribute)
+ << (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
+ ? 0
+ : 1)
+ << 2;
+ return;
+ }
+ // The second argument, if present, must be an unsigned integer.
+ unsigned TypeSize =
+ Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64
+ ? 64
+ : 32;
+ if (NumParams == 2 &&
+ (!getFunctionOrMethodParamType(D, 1)->isUnsignedIntegerType() ||
+ Context.getTypeSize(getFunctionOrMethodParamType(D, 1)) != TypeSize)) {
+ Diag(getFunctionOrMethodParamRange(D, 1).getBegin(),
+ diag::err_anyx86_interrupt_attribute)
+ << (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
+ ? 0
+ : 1)
+ << 3 << Context.getIntTypeForBitwidth(TypeSize, /*Signed=*/false);
+ return;
+ }
+ D->addAttr(::new (Context) AnyX86InterruptAttr(Context, AL));
+ D->addAttr(UsedAttr::CreateImplicit(Context));
+}
+
+void SemaX86::handleForceAlignArgPointerAttr(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)) {
+ Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
+ return;
+ }
+
+ D->addAttr(::new (getASTContext())
+ X86ForceAlignArgPointerAttr(getASTContext(), AL));
+}
+
} // namespace clang
More information about the cfe-commits
mailing list