From 6b755b0cf4ddfdc14b0371fd6e361c9b6d0ff702 Mon Sep 17 00:00:00 2001 From: Vlad Serebrennikov Date: Wed, 5 Jun 2024 09:46:37 +0400 Subject: [PATCH] [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. --- clang/include/clang/Sema/Attr.h | 156 + clang/include/clang/Sema/Sema.h | 100 +- clang/include/clang/Sema/SemaARM.h | 11 + clang/include/clang/Sema/SemaAVR.h | 32 + clang/include/clang/Sema/SemaBPF.h | 7 + clang/include/clang/Sema/SemaHLSL.h | 8 + clang/include/clang/Sema/SemaM68k.h | 30 + clang/include/clang/Sema/SemaMIPS.h | 4 + clang/include/clang/Sema/SemaMSP430.h | 30 + clang/include/clang/Sema/SemaObjC.h | 52 +- clang/include/clang/Sema/SemaOpenCL.h | 35 + clang/include/clang/Sema/SemaOpenMP.h | 3 + clang/include/clang/Sema/SemaRISCV.h | 5 + clang/include/clang/Sema/SemaSYCL.h | 4 + clang/include/clang/Sema/SemaSwift.h | 59 + clang/include/clang/Sema/SemaX86.h | 6 + clang/lib/Sema/CMakeLists.txt | 5 + clang/lib/Sema/Sema.cpp | 10 + clang/lib/Sema/SemaAPINotes.cpp | 5 +- clang/lib/Sema/SemaARM.cpp | 196 ++ clang/lib/Sema/SemaAVR.cpp | 49 + clang/lib/Sema/SemaBPF.cpp | 20 + clang/lib/Sema/SemaDecl.cpp | 3 +- clang/lib/Sema/SemaDeclAttr.cpp | 2898 +---------------- clang/lib/Sema/SemaHLSL.cpp | 228 ++ clang/lib/Sema/SemaM68k.cpp | 56 + clang/lib/Sema/SemaMIPS.cpp | 60 + clang/lib/Sema/SemaMSP430.cpp | 78 + clang/lib/Sema/SemaObjC.cpp | 772 +++++ clang/lib/Sema/SemaOpenCL.cpp | 99 + clang/lib/Sema/SemaOpenMP.cpp | 38 + clang/lib/Sema/SemaRISCV.cpp | 65 + clang/lib/Sema/SemaSYCL.cpp | 41 + clang/lib/Sema/SemaSwift.cpp | 765 +++++ .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 +- clang/lib/Sema/SemaType.cpp | 6 +- clang/lib/Sema/SemaX86.cpp | 94 + 37 files changed, 3254 insertions(+), 2784 deletions(-) create mode 100644 clang/include/clang/Sema/SemaAVR.h create mode 100644 clang/include/clang/Sema/SemaM68k.h create mode 100644 clang/include/clang/Sema/SemaMSP430.h create mode 100644 clang/include/clang/Sema/SemaOpenCL.h create mode 100644 clang/include/clang/Sema/SemaSwift.h create mode 100644 clang/lib/Sema/SemaAVR.cpp create mode 100644 clang/lib/Sema/SemaM68k.cpp create mode 100644 clang/lib/Sema/SemaMSP430.cpp create mode 100644 clang/lib/Sema/SemaOpenCL.cpp create mode 100644 clang/lib/Sema/SemaSwift.cpp diff --git a/clang/include/clang/Sema/Attr.h b/clang/include/clang/Sema/Attr.h index 1133862568a6c2..3f0b10212789a4 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(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(D) || isa(D) || + isa(D) || isa(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(FnTy); + return isa(D) || isa(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(FnTy)->getNumParams(); + if (const auto *BD = dyn_cast(D)) + return BD->getNumParams(); + return cast(D)->param_size(); +} + +inline const ParmVarDecl *getFunctionOrMethodParam(const Decl *D, + unsigned Idx) { + if (const auto *FD = dyn_cast(D)) + return FD->getParamDecl(Idx); + if (const auto *MD = dyn_cast(D)) + return MD->getParamDecl(Idx); + if (const auto *BD = dyn_cast(D)) + return BD->getParamDecl(Idx); + return nullptr; +} + +inline QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) { + if (const FunctionType *FnTy = D->getFunctionType()) + return cast(FnTy)->getParamType(Idx); + if (const auto *BD = dyn_cast(D)) + return BD->getParamDecl(Idx)->getType(); + + return cast(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(D)->getReturnType(); +} + +inline SourceRange getFunctionOrMethodResultSourceRange(const Decl *D) { + if (const auto *FD = dyn_cast(D)) + return FD->getReturnTypeSourceRange(); + if (const auto *MD = dyn_cast(D)) + return MD->getReturnTypeSourceRange(); + return SourceRange(); +} + +inline bool isFunctionOrMethodVariadic(const Decl *D) { + if (const FunctionType *FnTy = D->getFunctionType()) + return cast(FnTy)->isVariadic(); + if (const auto *BD = dyn_cast(D)) + return BD->isVariadic(); + return cast(D)->isVariadic(); +} + +inline bool isInstanceMethod(const Decl *D) { + if (const auto *MethodDecl = dyn_cast(D)) + return MethodDecl->isInstance(); + return false; +} + +/// Diagnose mutually exclusive attributes when present on a given +/// declaration. Returns true if diagnosed. +template +bool checkAttrMutualExclusion(SemaBase &S, Decl *D, const ParsedAttr &AL) { + if (const auto *A = D->getAttr()) { + 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 +bool checkAttrMutualExclusion(SemaBase &S, Decl *D, const Attr &AL) { + if (const auto *A = D->getAttr()) { + 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 +const SemaBase::SemaDiagnosticBuilder & +appendDiagnostics(const SemaBase::SemaDiagnosticBuilder &Bldr) { + return Bldr; +} + +template +const SemaBase::SemaDiagnosticBuilder & +appendDiagnostics(const SemaBase::SemaDiagnosticBuilder &Bldr, T &&ExtraArg, + DiagnosticArgs &&...ExtraArgs) { + return appendDiagnostics(Bldr << std::forward(ExtraArg), + std::forward(ExtraArgs)...); +} + +/// Applies the given attribute to the Decl without performing any +/// additional semantic checking. +template +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 +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(ExtraArgs)...); + return; + } + handleSimpleAttribute(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 7dea2b6826cfdb..4d4579fcfd456b 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 AMDGPUPtr; std::unique_ptr ARMPtr; + std::unique_ptr AVRPtr; std::unique_ptr BPFPtr; std::unique_ptr CodeCompletionPtr; std::unique_ptr CUDAPtr; std::unique_ptr HLSLPtr; std::unique_ptr HexagonPtr; std::unique_ptr LoongArchPtr; + std::unique_ptr M68kPtr; std::unique_ptr MIPSPtr; + std::unique_ptr MSP430Ptr; std::unique_ptr NVPTXPtr; std::unique_ptr ObjCPtr; std::unique_ptr OpenACCPtr; + std::unique_ptr OpenCLPtr; std::unique_ptr OpenMPPtr; std::unique_ptr PPCPtr; std::unique_ptr PseudoObjectPtr; std::unique_ptr RISCVPtr; std::unique_ptr SYCLPtr; + std::unique_ptr SwiftPtr; std::unique_ptr SystemZPtr; std::unique_ptr WasmPtr; std::unique_ptr 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 + 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 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 02698a33abd55e..6478c0beb715d3 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 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 00000000000000..708da3a6026ace --- /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 a3bf59128d2548..0182ccfe508a7b 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 eac1f7c07c85de..e145f5e7f43f85 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -25,6 +25,7 @@ #include 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 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 00000000000000..5a9767d5ea5216 --- /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 3f1781b36efd93..6366dce57626af 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 00000000000000..e1034aefe88164 --- /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 a9a0d167809569..91430797e5ed82 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 00000000000000..0d80c4b4c0b561 --- /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 51981e1c9a8b93..3edf1cc7c12f2b 100644 --- a/clang/include/clang/Sema/SemaOpenMP.h +++ b/clang/include/clang/Sema/SemaOpenMP.h @@ -42,6 +42,7 @@ #include namespace clang { +class ParsedAttr; class SemaOpenMP : public SemaBase { public: @@ -1348,6 +1349,8 @@ class SemaOpenMP : public SemaBase { SourceLocation LLoc, SourceLocation RLoc, ArrayRef 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 b6dd81f8d4d808..48d15c411bddde 100644 --- a/clang/include/clang/Sema/SemaRISCV.h +++ b/clang/include/clang/Sema/SemaRISCV.h @@ -24,6 +24,8 @@ #include 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 f0dcb92ee9ab3e..363178546a236c 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 00000000000000..a5561d756affd1 --- /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 e322483294ec70..e53aaf229c38dd 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 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 c9abf58fcbd29e..f152d243d39a5b 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 582adcfa84c464..a612dcd4b4d031 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(*this)), ARMPtr(std::make_unique(*this)), + AVRPtr(std::make_unique(*this)), BPFPtr(std::make_unique(*this)), CodeCompletionPtr( std::make_unique(*this, CodeCompleter)), @@ -225,15 +231,19 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, HLSLPtr(std::make_unique(*this)), HexagonPtr(std::make_unique(*this)), LoongArchPtr(std::make_unique(*this)), + M68kPtr(std::make_unique(*this)), MIPSPtr(std::make_unique(*this)), + MSP430Ptr(std::make_unique(*this)), NVPTXPtr(std::make_unique(*this)), ObjCPtr(std::make_unique(*this)), OpenACCPtr(std::make_unique(*this)), + OpenCLPtr(std::make_unique(*this)), OpenMPPtr(std::make_unique(*this)), PPCPtr(std::make_unique(*this)), PseudoObjectPtr(std::make_unique(*this)), RISCVPtr(std::make_unique(*this)), SYCLPtr(std::make_unique(*this)), + SwiftPtr(std::make_unique(*this)), SystemZPtr(std::make_unique(*this)), WasmPtr(std::make_unique(*this)), X86Ptr(std::make_unique(*this)), diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp index c80b08e361cfa6..bc1628f5b71636 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 da37ccef051a68..02e68dbdb2e9dc 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 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 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(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 NewState; + if (const auto *ExistingAttr = D->getAttr()) { + 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(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(); + 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(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 00000000000000..47368780b62037 --- /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(*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(*this, D, AL); +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaBPF.cpp b/clang/lib/Sema/SemaBPF.cpp index bde1a26f1ebc0e..7c00084d62dd9a 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 @@ -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()) + continue; + + D->addAttr(BPFPreserveAccessIndexAttr::CreateImplicit(getASTContext())); + if (auto *Rec = dyn_cast(D)) + handlePreserveAIRecord(Rec); + } +} + +void SemaBPF::handlePreserveAccessIndexAttr(Decl *D, const ParsedAttr &AL) { + auto *Rec = cast(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 7ff05ae514ebec..a6734ef8c30aa8 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(Attr)) NewAttr = S.mergeMinSizeAttr(D, *MA); else if (const auto *SNA = dyn_cast(Attr)) - NewAttr = S.mergeSwiftNameAttr(D, *SNA, SNA->getName()); + NewAttr = S.Swift().mergeNameAttr(D, *SNA, SNA->getName()); else if (const auto *OA = dyn_cast(Attr)) NewAttr = S.mergeOptimizeNoneAttr(D, *OA); else if (const auto *InternalLinkageA = dyn_cast(Attr)) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 7c1fb23b90728c..ce6b5b1ff6f931 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(D) || isa(D) || isa(D) || - isa(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(FnTy); - return isa(D) || isa(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(FnTy)->getNumParams(); - if (const auto *BD = dyn_cast(D)) - return BD->getNumParams(); - return cast(D)->param_size(); -} - -static const ParmVarDecl *getFunctionOrMethodParam(const Decl *D, - unsigned Idx) { - if (const auto *FD = dyn_cast(D)) - return FD->getParamDecl(Idx); - if (const auto *MD = dyn_cast(D)) - return MD->getParamDecl(Idx); - if (const auto *BD = dyn_cast(D)) - return BD->getParamDecl(Idx); - return nullptr; -} - -static QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) { - if (const FunctionType *FnTy = D->getFunctionType()) - return cast(FnTy)->getParamType(Idx); - if (const auto *BD = dyn_cast(D)) - return BD->getParamDecl(Idx)->getType(); - - return cast(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(D)->getReturnType(); -} - -static SourceRange getFunctionOrMethodResultSourceRange(const Decl *D) { - if (const auto *FD = dyn_cast(D)) - return FD->getReturnTypeSourceRange(); - if (const auto *MD = dyn_cast(D)) - return MD->getReturnTypeSourceRange(); - return SourceRange(); -} - -static bool isFunctionOrMethodVariadic(const Decl *D) { - if (const FunctionType *FnTy = D->getFunctionType()) - return cast(FnTy)->isVariadic(); - if (const auto *BD = dyn_cast(D)) - return BD->isVariadic(); - return cast(D)->isVariadic(); -} - -static bool isInstanceMethod(const Decl *D) { - if (const auto *MethodDecl = dyn_cast(D)) - return MethodDecl->isInstance(); - return false; -} - -static inline bool isNSStringType(QualType T, ASTContext &Ctx, - bool AllowNSAttributedString = false) { - const auto *PT = T->getAs(); - 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(); - if (!PT) - return false; - - const auto *RT = PT->getPointeeType()->getAs(); - 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 -static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { - if (const auto *A = D->getAttr()) { - 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 -static bool checkAttrMutualExclusion(Sema &S, Decl *D, const Attr &AL) { - if (const auto *A = D->getAttr()) { - 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 -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 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 -static void handleSimpleAttribute(Sema &S, Decl *D, - const AttributeCommonInfo &CI) { - D->addAttr(::new (S.Context) AttrType(S.Context, CI)); -} - -template -static const Sema::SemaDiagnosticBuilder& -appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr) { - return Bldr; -} - -template -static const Sema::SemaDiagnosticBuilder& -appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr, T &&ExtraArg, - DiagnosticArgs &&... ExtraArgs) { - return appendDiagnostics(Bldr << std::forward(ExtraArg), - std::forward(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 -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(ExtraArgs)...); - return; - } - handleSimpleAttribute(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(D)) { - if (!VD->getType()->getAs()) { - S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type) - << AL << VD->getType() << 0; - return false; - } - } - else if (const auto *PD = dyn_cast(D)) { - if (!PD->getType()->getAs()) { - 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(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(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(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(D->getDeclContext())) { - S.Diag(AL.getLoc(), diag::err_objc_direct_on_protocol) << false; - return; - } - - if (S.getLangOpts().ObjCRuntime.allowsDirectDispatch()) { - handleSimpleAttribute(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(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(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(D)) { - QualType T = TD->getUnderlyingType(); - if (!T->isCARCBridgableType()) { - S.Diag(TD->getLocation(), diag::err_nsobject_attribute); - return; - } - } - else if (const auto *PD = dyn_cast(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(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(); - 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()->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()->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()->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()) { - 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(); - } - return ::new (Context) SwiftNameAttr(Context, SNA, Name); -} - OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, const AttributeCommonInfo &CI) { if (AlwaysInlineAttr *Inline = D->getAttr()) { @@ -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()) { - Ty = PtrType->getPointeeType(); - } else if (const auto *RefType = Ty->getAs()) { - 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()) { - Ty = PtrType->getPointeeType(); - } else if (const auto *RefType = Ty->getAs()) { - 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(D)->getType(); - - if (auto existingAttr = D->getAttr()) { - 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 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 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(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(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(D); - !CRD || !(CRD->isClass() || CRD->isStruct())) { - S.Diag(AL.getRange().getBegin(), diag::err_attribute_wrong_decl_type_str) - << AL << AL.isRegularKeywordAttribute() << "classes"; - return; - } - - handleSimpleAttribute(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(D); - switch (K) { - case RetainOwnershipKind::OS: - handleSimpleAttributeOrDiagnose( - *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( - *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( - *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(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(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(D)) { - ReturnType = PD->getType(); - } else if (const auto *FD = dyn_cast(D)) { - ReturnType = FD->getReturnType(); - } else if (const auto *Param = dyn_cast(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(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(D)) - SubjectKind = Method; - else if (isa(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(S, D, AL); - return; - case ParsedAttr::AT_CFReturnsNotRetained: - handleSimpleAttribute(S, D, AL); - return; - case ParsedAttr::AT_NSReturnsNotRetained: - handleSimpleAttribute(S, D, AL); - return; - case ParsedAttr::AT_CFReturnsRetained: - handleSimpleAttribute(S, D, AL); - return; - case ParsedAttr::AT_NSReturnsRetained: - handleSimpleAttribute(S, D, AL); - return; - case ParsedAttr::AT_OSReturnsRetained: - handleSimpleAttribute(S, D, AL); - return; - case ParsedAttr::AT_OSReturnsNotRetained: - handleSimpleAttribute(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(D)) - resultType = cast(D)->getReturnType(); - else - resultType = cast(D)->getType(); - - if (!resultType->isReferenceType() && - (!resultType->isPointerType() || resultType->isObjCRetainableType())) { - S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_return_type) - << SourceRange(loc) << Attrs - << (isa(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(D); - - const DeclContext *DC = Method->getDeclContext(); - if (const auto *PDecl = dyn_cast_if_present(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(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()) { - 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(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(Ctx) && - !(isa(Ctx) && - cast(Ctx)->IsClassExtension())) { - S.Diag(D->getLocation(), diag::err_designated_init_attr_non_init); - return; - } - - ObjCInterfaceDecl *IFace; - if (auto *CatDecl = dyn_cast(Ctx)) - IFace = CatDecl->getClassInterface(); - else - IFace = cast(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(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(D); - QualType QT = VD->getType(); - - if (!QT->isDependentType() && - !QT->isObjCLifetimeType()) { - S.Diag(AL.getLoc(), diag::err_objc_precise_lifetime_bad_type) - << QT; - return; - } - - Qualifiers::ObjCLifetime Lifetime = QT.getObjCLifetime(); - - // If we have no lifetime yet, check the lifetime we're presumably - // going to infer. - if (Lifetime == Qualifiers::OCL_None && !QT->isDependentType()) - Lifetime = QT->getObjCARCImplicitLifetime(); - - switch (Lifetime) { - case Qualifiers::OCL_None: - assert(QT->isDependentType() && - "didn't infer lifetime for non-dependent type?"); - break; - - case Qualifiers::OCL_Weak: // meaningful - case Qualifiers::OCL_Strong: // meaningful - break; - - case Qualifiers::OCL_ExplicitNone: - case Qualifiers::OCL_Autoreleasing: - S.Diag(AL.getLoc(), diag::warn_objc_precise_lifetime_meaningless) - << (Lifetime == Qualifiers::OCL_Autoreleasing); - break; - } - - D->addAttr(::new (S.Context) ObjCPreciseLifetimeAttr(S.Context, AL)); -} - -static void handleSwiftAttrAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - // Make sure that there is a string literal as the annotation's single - // argument. - StringRef Str; - if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) - return; - - D->addAttr(::new (S.Context) SwiftAttrAttr(S.Context, AL, Str)); -} - -static void handleSwiftBridge(Sema &S, Decl *D, const ParsedAttr &AL) { - // Make sure that there is a string literal as the annotation's single - // argument. - StringRef BT; - if (!S.checkStringLiteralArgumentAttr(AL, 0, BT)) - return; - - // Warn about duplicate attributes if they have different arguments, but drop - // any duplicate attributes regardless. - if (const auto *Other = D->getAttr()) { - 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(); - if (!PT) - return false; - - QualType Pointee = PT->getPointeeType(); - - // Check for NSError**. - if (const auto *OPT = Pointee->getAs()) - if (const auto *ID = OPT->getInterfaceDecl()) - if (ID->getIdentifier() == S.ObjC().getNSErrorIdent()) - return true; - - // Check for CFError**. - if (const auto *PT = Pointee->getAs()) - if (const auto *RT = PT->getPointeeType()->getAs()) - 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(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(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(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(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() - ->getPointeeType() - ->getAs(); - ArrayRef 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()) { - if (const auto *ID = ObjCPtrTy->getInterfaceDecl()) { - if (ID->getIdentifier() == S.ObjC().getNSErrorIdent()) { - AnyErrorParams = true; - break; - } - } - } - // Check for CFError *. - if (const auto *PtrTy = Param->getAs()) { - if (const auto *RT = PtrTy->getPointeeType()->getAs()) { - 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(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()) - checkSwiftAsyncErrorBlock(S, D, ErrorAttr, AsyncAttr); -} - -// For a function, this will validate a compound Swift name, e.g. -// init(foo:bar:baz:) or controllerForName(_:), 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 -// context.identifier 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 SelfLocation; - unsigned NewValueCount = 0; - std::optional 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(D) || isa(D)) { - ArrayRef Params; - unsigned ParamCount; - - if (const auto *Method = dyn_cast(D)) { - ParamCount = Method->getSelector().getNumArgs(); - Params = Method->parameters().slice(0, ParamCount); - } else { - const auto *F = cast(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(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(D) || isa(D) || - isa(D) || isa(D) || - isa(D) || isa(D) || isa(D) || - isa(D) || isa(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(D)->getIdentifier()->getName(); - if (!isa(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(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(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()->getPointeeType(); - if (!BlockTy->castAs()->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()) - 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()) - 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(D)) { - S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node) - << AL << "parameter"; - return; - } - - auto *VD = cast(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(D) || !isa(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(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()) - 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(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(AL.getArgAsExpr(0)); - std::optional 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(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(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(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(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(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()) - continue; - - D->addAttr(BPFPreserveAccessIndexAttr::CreateImplicit(S.Context)); - if (auto *Rec = dyn_cast(D)) - handleBPFPreserveAIRecord(S, Rec); - } -} - -static void handleBPFPreserveAccessIndexAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { - auto *Rec = cast(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()) { 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()) { - 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(D); - if (VD && VD->getType()->isFunctionPointerType()) - return; - // Also don't warn on function pointer typedefs. - const auto *TD = dyn_cast(D); - if (TD && (TD->getUnderlyingType()->isFunctionPointerType() || - TD->getUnderlyingType()->isFunctionType())) - return; - // Attribute can only be applied to function types. - if (!isa(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(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()) { - if (D->getAttr()->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(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(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(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(S, D, AL); -} - static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) { if (!cast(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(D)) { - assert(!isa(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(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(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(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 NewState; - if (const auto *ExistingAttr = D->getAttr()) { - 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(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(); - 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(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(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(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( - 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( - 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(S, D, AL); @@ -9331,7 +6717,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, handleWorkGroupSize(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(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(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(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()) - handleBPFPreserveAIRecord(*this, cast(D)); + BPF().handlePreserveAIRecord(cast(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 9e614ae99f37d2..0a2face7afe65a 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()) + 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(D)) { + Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node) + << AL << "parameter"; + return; + } + + auto *VD = cast(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(D) || !isa(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(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()) + 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(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 00000000000000..f091827092f831 --- /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(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 df5328fbf66404..269d927903c5d6 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(*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 00000000000000..4038a1ff61d63c --- /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(AL.getArgAsExpr(0)); + std::optional 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 1e6cc21a487044..d396258cfc7d18 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(); + 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(); + if (!PT) + return false; + + const auto *RT = PT->getPointeeType()->getAs(); + 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(D)) { + if (!VD->getType()->getAs()) { + S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type) + << AL << VD->getType() << 0; + return false; + } + } else if (const auto *PD = dyn_cast(D)) { + if (!PD->getType()->getAs()) { + 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(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(D->getDeclContext())) { + Diag(AL.getLoc(), diag::err_objc_direct_on_protocol) << false; + return; + } + + if (getLangOpts().ObjCRuntime.allowsDirectDispatch()) { + handleSimpleAttribute(*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(*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(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(D)) { + QualType T = TD->getUnderlyingType(); + if (!T->isCARCBridgableType()) { + Diag(TD->getLocation(), diag::err_nsobject_attribute); + return; + } + } else if (const auto *PD = dyn_cast(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(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(D); + switch (K) { + case Sema::RetainOwnershipKind::OS: + handleSimpleAttributeOrDiagnose( + *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( + *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( + *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(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(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(D)) { + ReturnType = PD->getType(); + } else if (const auto *FD = dyn_cast(D)) { + ReturnType = FD->getReturnType(); + } else if (const auto *Param = dyn_cast(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(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(D)) + SubjectKind = Method; + else if (isa(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(*this, D, AL); + return; + case ParsedAttr::AT_CFReturnsNotRetained: + handleSimpleAttribute(*this, D, AL); + return; + case ParsedAttr::AT_NSReturnsNotRetained: + handleSimpleAttribute(*this, D, AL); + return; + case ParsedAttr::AT_CFReturnsRetained: + handleSimpleAttribute(*this, D, AL); + return; + case ParsedAttr::AT_NSReturnsRetained: + handleSimpleAttribute(*this, D, AL); + return; + case ParsedAttr::AT_OSReturnsRetained: + handleSimpleAttribute(*this, D, AL); + return; + case ParsedAttr::AT_OSReturnsNotRetained: + handleSimpleAttribute(*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(D)) + resultType = cast(D)->getReturnType(); + else + resultType = cast(D)->getType(); + + if (!resultType->isReferenceType() && + (!resultType->isPointerType() || resultType->isObjCRetainableType())) { + Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_return_type) + << SourceRange(loc) << Attrs + << (isa(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(D); + + const DeclContext *DC = Method->getDeclContext(); + if (const auto *PDecl = dyn_cast_if_present(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(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()) { + 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(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(Ctx) && + !(isa(Ctx) && + cast(Ctx)->IsClassExtension())) { + Diag(D->getLocation(), diag::err_designated_init_attr_non_init); + return; + } + + ObjCInterfaceDecl *IFace; + if (auto *CatDecl = dyn_cast(Ctx)) + IFace = CatDecl->getClassInterface(); + else + IFace = cast(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(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(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(D)) { + assert(!isa(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(*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(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(*this, D, AL); +} + } // namespace clang diff --git a/clang/lib/Sema/SemaOpenCL.cpp b/clang/lib/Sema/SemaOpenCL.cpp new file mode 100644 index 00000000000000..b3b495a15e02c3 --- /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()) { + if (D->getAttr()->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(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(); + 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 99528c2a4f1f44..6e6815328e9139 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 #include @@ -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 ea6e3f75490bc2..fd4fc15c1fd79e 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()) { + 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 18f6d8f0304737..2b55c598d55c03 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(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(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(*this, D, AL); +} diff --git a/clang/lib/Sema/SemaSwift.cpp b/clang/lib/Sema/SemaSwift.cpp new file mode 100644 index 00000000000000..bf56ae8ac76d57 --- /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()) { + 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(); + } + 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()) { + Ty = PtrType->getPointeeType(); + } else if (const auto *RefType = Ty->getAs()) { + 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()) { + Ty = PtrType->getPointeeType(); + } else if (const auto *RefType = Ty->getAs()) { + 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 different arguments, but drop + // any duplicate attributes regardless. + if (const auto *Other = D->getAttr()) { + 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(); + if (!PT) + return false; + + QualType Pointee = PT->getPointeeType(); + + // Check for NSError**. + if (const auto *OPT = Pointee->getAs()) + if (const auto *ID = OPT->getInterfaceDecl()) + if (ID->getIdentifier() == S.ObjC().getNSErrorIdent()) + return true; + + // Check for CFError**. + if (const auto *PT = Pointee->getAs()) + if (const auto *RT = PT->getPointeeType()->getAs()) + 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(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(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(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(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() + ->getPointeeType() + ->getAs(); + ArrayRef 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()) { + if (const auto *ID = ObjCPtrTy->getInterfaceDecl()) { + if (ID->getIdentifier() == S.ObjC().getNSErrorIdent()) { + AnyErrorParams = true; + break; + } + } + } + // Check for CFError *. + if (const auto *PtrTy = Param->getAs()) { + if (const auto *RT = PtrTy->getPointeeType()->getAs()) { + 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(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()) + checkSwiftAsyncErrorBlock(SemaRef, D, ErrorAttr, AsyncAttr); +} + +// For a function, this will validate a compound Swift name, e.g. +// init(foo:bar:baz:) or controllerForName(_:), 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 +// context.identifier 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 SelfLocation; + unsigned NewValueCount = 0; + std::optional 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(D) || isa(D)) { + ArrayRef Params; + unsigned ParamCount; + + if (const auto *Method = dyn_cast(D)) { + ParamCount = Method->getSelector().getNumArgs(); + Params = Method->parameters().slice(0, ParamCount); + } else { + const auto *F = cast(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(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(D) || isa(D) || + isa(D) || isa(D) || + isa(D) || isa(D) || isa(D) || + isa(D) || isa(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(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()->getPointeeType(); + if (!BlockTy->castAs()->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()) + checkSwiftAsyncErrorBlock(SemaRef, D, ErrorAttr, AsyncAttr); +} + +void SemaSwift::AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI, + ParameterABI abi) { + ASTContext &Context = getASTContext(); + QualType type = cast(D)->getType(); + + if (auto existingAttr = D->getAttr()) { + 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 4c8eaf2d4ebf68..0681520764d9a0 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(TmplAttr)) { - AddParameterABIAttr(New, *ABIAttr, ABIAttr->getABI()); + Swift().AddParameterABIAttr(New, *ABIAttr, ABIAttr->getABI()); continue; } if (isa(TmplAttr) || isa(TmplAttr) || isa(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 7cec82c7010280..441fdcca0758f9 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 ffac1afc5d7822..be26454ce909d5 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(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(D); + if (VD && VD->getType()->isFunctionPointerType()) + return; + // Also don't warn on function pointer typedefs. + const auto *TD = dyn_cast(D); + if (TD && (TD->getUnderlyingType()->isFunctionPointerType() || + TD->getUnderlyingType()->isFunctionType())) + return; + // Attribute can only be applied to function types. + if (!isa(D)) { + Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; + return; + } + + D->addAttr(::new (getASTContext()) + X86ForceAlignArgPointerAttr(getASTContext(), AL)); +} + } // namespace clang