Skip to content

[clang] Split up SemaDeclAttr.cpp #93966

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 156 additions & 0 deletions clang/include/clang/Sema/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -32,5 +41,152 @@ inline bool isFunctionOrMethodOrBlockForAttrSubject(const Decl *D) {
return isFuncOrMethodForAttrSubject(D) || llvm::isa<BlockDecl>(D);
}

/// Return true if the given decl has a declarator that should have
/// been processed by Sema::GetTypeForDeclarator.
inline bool hasDeclarator(const Decl *D) {
// In some sense, TypedefDecl really *ought* to be a DeclaratorDecl.
return isa<DeclaratorDecl>(D) || isa<BlockDecl>(D) ||
isa<TypedefNameDecl>(D) || isa<ObjCPropertyDecl>(D);
}

/// hasFunctionProto - Return true if the given decl has a argument
/// information. This decl should have already passed
/// isFuncOrMethodForAttrSubject or isFunctionOrMethodOrBlockForAttrSubject.
inline bool hasFunctionProto(const Decl *D) {
if (const FunctionType *FnTy = D->getFunctionType())
return isa<FunctionProtoType>(FnTy);
return isa<ObjCMethodDecl>(D) || isa<BlockDecl>(D);
}

/// getFunctionOrMethodNumParams - Return number of function or method
/// parameters. It is an error to call this on a K&R function (use
/// hasFunctionProto first).
inline unsigned getFunctionOrMethodNumParams(const Decl *D) {
if (const FunctionType *FnTy = D->getFunctionType())
return cast<FunctionProtoType>(FnTy)->getNumParams();
if (const auto *BD = dyn_cast<BlockDecl>(D))
return BD->getNumParams();
return cast<ObjCMethodDecl>(D)->param_size();
}

inline const ParmVarDecl *getFunctionOrMethodParam(const Decl *D,
unsigned Idx) {
if (const auto *FD = dyn_cast<FunctionDecl>(D))
return FD->getParamDecl(Idx);
if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
return MD->getParamDecl(Idx);
if (const auto *BD = dyn_cast<BlockDecl>(D))
return BD->getParamDecl(Idx);
return nullptr;
}

inline QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) {
if (const FunctionType *FnTy = D->getFunctionType())
return cast<FunctionProtoType>(FnTy)->getParamType(Idx);
if (const auto *BD = dyn_cast<BlockDecl>(D))
return BD->getParamDecl(Idx)->getType();

return cast<ObjCMethodDecl>(D)->parameters()[Idx]->getType();
}

inline SourceRange getFunctionOrMethodParamRange(const Decl *D, unsigned Idx) {
if (auto *PVD = getFunctionOrMethodParam(D, Idx))
return PVD->getSourceRange();
return SourceRange();
}

inline QualType getFunctionOrMethodResultType(const Decl *D) {
if (const FunctionType *FnTy = D->getFunctionType())
return FnTy->getReturnType();
return cast<ObjCMethodDecl>(D)->getReturnType();
}

inline SourceRange getFunctionOrMethodResultSourceRange(const Decl *D) {
if (const auto *FD = dyn_cast<FunctionDecl>(D))
return FD->getReturnTypeSourceRange();
if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
return MD->getReturnTypeSourceRange();
return SourceRange();
}

inline bool isFunctionOrMethodVariadic(const Decl *D) {
if (const FunctionType *FnTy = D->getFunctionType())
return cast<FunctionProtoType>(FnTy)->isVariadic();
if (const auto *BD = dyn_cast<BlockDecl>(D))
return BD->isVariadic();
return cast<ObjCMethodDecl>(D)->isVariadic();
}

inline bool isInstanceMethod(const Decl *D) {
if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(D))
return MethodDecl->isInstance();
return false;
}

/// Diagnose mutually exclusive attributes when present on a given
/// declaration. Returns true if diagnosed.
template <typename AttrTy>
bool checkAttrMutualExclusion(SemaBase &S, Decl *D, const ParsedAttr &AL) {
if (const auto *A = D->getAttr<AttrTy>()) {
S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
<< AL << A
<< (AL.isRegularKeywordAttribute() || A->isRegularKeywordAttribute());
S.Diag(A->getLocation(), diag::note_conflicting_attribute);
return true;
}
return false;
}

template <typename AttrTy>
bool checkAttrMutualExclusion(SemaBase &S, Decl *D, const Attr &AL) {
if (const auto *A = D->getAttr<AttrTy>()) {
S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible)
<< &AL << A
<< (AL.isRegularKeywordAttribute() || A->isRegularKeywordAttribute());
Diag(A->getLocation(), diag::note_conflicting_attribute);
return true;
}
return false;
}

template <typename... DiagnosticArgs>
const SemaBase::SemaDiagnosticBuilder &
appendDiagnostics(const SemaBase::SemaDiagnosticBuilder &Bldr) {
return Bldr;
}

template <typename T, typename... DiagnosticArgs>
const SemaBase::SemaDiagnosticBuilder &
appendDiagnostics(const SemaBase::SemaDiagnosticBuilder &Bldr, T &&ExtraArg,
DiagnosticArgs &&...ExtraArgs) {
return appendDiagnostics(Bldr << std::forward<T>(ExtraArg),
std::forward<DiagnosticArgs>(ExtraArgs)...);
}

/// Applies the given attribute to the Decl without performing any
/// additional semantic checking.
template <typename AttrType>
void handleSimpleAttribute(SemaBase &S, Decl *D,
const AttributeCommonInfo &CI) {
D->addAttr(::new (S.getASTContext()) AttrType(S.getASTContext(), CI));
}

/// Add an attribute @c AttrType to declaration @c D, provided that
/// @c PassesCheck is true.
/// Otherwise, emit diagnostic @c DiagID, passing in all parameters
/// specified in @c ExtraArgs.
template <typename AttrType, typename... DiagnosticArgs>
void handleSimpleAttributeOrDiagnose(SemaBase &S, Decl *D,
const AttributeCommonInfo &CI,
bool PassesCheck, unsigned DiagID,
DiagnosticArgs &&...ExtraArgs) {
if (!PassesCheck) {
SemaBase::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID);
appendDiagnostics(DB, std::forward<DiagnosticArgs>(ExtraArgs)...);
return;
}
handleSimpleAttribute<AttrType>(S, D, CI);
}

} // namespace clang
#endif // LLVM_CLANG_SEMA_ATTR_H
100 changes: 82 additions & 18 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1011,6 +1017,11 @@ class Sema final : public SemaBase {
return *ARMPtr;
}

SemaAVR &AVR() {
assert(AVRPtr);
return *AVRPtr;
}

SemaBPF &BPF() {
assert(BPFPtr);
return *BPFPtr;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -1086,6 +1112,11 @@ class Sema final : public SemaBase {
return *SYCLPtr;
}

SemaSwift &Swift() {
assert(SwiftPtr);
return *SwiftPtr;
}

SemaSystemZ &SystemZ() {
assert(SystemZPtr);
return *SystemZPtr;
Expand Down Expand Up @@ -1133,21 +1164,26 @@ class Sema final : public SemaBase {

std::unique_ptr<SemaAMDGPU> AMDGPUPtr;
std::unique_ptr<SemaARM> ARMPtr;
std::unique_ptr<SemaAVR> AVRPtr;
std::unique_ptr<SemaBPF> BPFPtr;
std::unique_ptr<SemaCodeCompletion> CodeCompletionPtr;
std::unique_ptr<SemaCUDA> CUDAPtr;
std::unique_ptr<SemaHLSL> HLSLPtr;
std::unique_ptr<SemaHexagon> HexagonPtr;
std::unique_ptr<SemaLoongArch> LoongArchPtr;
std::unique_ptr<SemaM68k> M68kPtr;
std::unique_ptr<SemaMIPS> MIPSPtr;
std::unique_ptr<SemaMSP430> MSP430Ptr;
std::unique_ptr<SemaNVPTX> NVPTXPtr;
std::unique_ptr<SemaObjC> ObjCPtr;
std::unique_ptr<SemaOpenACC> OpenACCPtr;
std::unique_ptr<SemaOpenCL> OpenCLPtr;
std::unique_ptr<SemaOpenMP> OpenMPPtr;
std::unique_ptr<SemaPPC> PPCPtr;
std::unique_ptr<SemaPseudoObject> PseudoObjectPtr;
std::unique_ptr<SemaRISCV> RISCVPtr;
std::unique_ptr<SemaSYCL> SYCLPtr;
std::unique_ptr<SemaSwift> SwiftPtr;
std::unique_ptr<SemaSystemZ> SystemZPtr;
std::unique_ptr<SemaWasm> WasmPtr;
std::unique_ptr<SemaX86> X86Ptr;
Expand Down Expand Up @@ -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);
Expand All @@ -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.
Expand All @@ -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);
Expand Down Expand Up @@ -3825,6 +3843,52 @@ class Sema final : public SemaBase {

void redelayDiagnostics(sema::DelayedDiagnosticPool &pool);

/// Check if IdxExpr is a valid parameter index for a function or
/// instance method D. May output an error.
///
/// \returns true if IdxExpr is a valid index.
template <typename AttrInfo>
bool checkFunctionOrMethodParameterIndex(const Decl *D, const AttrInfo &AI,
unsigned AttrArgNum,
const Expr *IdxExpr, ParamIdx &Idx,
bool CanIndexImplicitThis = false) {
assert(isFunctionOrMethodOrBlockForAttrSubject(D));

// In C++ the implicit 'this' function parameter also counts.
// Parameters are counted from one.
bool HP = hasFunctionProto(D);
bool HasImplicitThisParam = isInstanceMethod(D);
bool IV = HP && isFunctionOrMethodVariadic(D);
unsigned NumParams =
(HP ? getFunctionOrMethodNumParams(D) : 0) + HasImplicitThisParam;

std::optional<llvm::APSInt> IdxInt;
if (IdxExpr->isTypeDependent() ||
!(IdxInt = IdxExpr->getIntegerConstantExpr(Context))) {
Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type)
<< &AI << AttrArgNum << AANT_ArgumentIntegerConstant
<< IdxExpr->getSourceRange();
return false;
}

unsigned IdxSource = IdxInt->getLimitedValue(UINT_MAX);
if (IdxSource < 1 || (!IV && IdxSource > NumParams)) {
Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds)
<< &AI << AttrArgNum << IdxExpr->getSourceRange();
return false;
}
if (HasImplicitThisParam && !CanIndexImplicitThis) {
if (IdxSource == 1) {
Diag(getAttrLoc(AI), diag::err_attribute_invalid_implicit_this_argument)
<< &AI << IdxExpr->getSourceRange();
return false;
}
}

Idx = ParamIdx(IdxSource, D);
return true;
}

///@}

//
Expand Down
Loading
Loading