diff options
Diffstat (limited to 'lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 622 |
1 files changed, 499 insertions, 123 deletions
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 0e10804a2e..f8a34573f3 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1,9 +1,8 @@ //===--- SemaDeclAttr.cpp - Declaration Attribute Handling ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -246,11 +245,11 @@ static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr, !Expr->isIntegerConstantExpr(I, S.Context)) { if (Idx != UINT_MAX) S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) - << AI << Idx << AANT_ArgumentIntegerConstant + << &AI << Idx << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); else S.Diag(getAttrLoc(AI), diag::err_attribute_argument_type) - << AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); + << &AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); return false; } @@ -262,7 +261,7 @@ static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr, if (StrictlyUnsigned && I.isSigned() && I.isNegative()) { S.Diag(getAttrLoc(AI), diag::err_attribute_requires_positive_integer) - << AI << /*non-negative*/ 1; + << &AI << /*non-negative*/ 1; return false; } @@ -717,7 +716,8 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, uint64_t ParamIdxFromOne = ArgValue.getZExtValue(); uint64_t ParamIdxFromZero = ParamIdxFromOne - 1; if (!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_range) + S.Diag(AL.getLoc(), + diag::err_attribute_argument_out_of_bounds_extra_info) << AL << Idx + 1 << NumParams; continue; } @@ -1119,7 +1119,7 @@ static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // __builtin_object_size. So, it has the same constraints as that second // argument; namely, it must be in the range [0, 3]. if (Type > 3) { - S.Diag(E->getBeginLoc(), diag::err_attribute_argument_outof_range) + S.Diag(E->getBeginLoc(), diag::err_attribute_argument_out_of_range) << AL << 0 << 3 << E->getSourceRange(); return; } @@ -2284,18 +2284,11 @@ static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y, return false; } -AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, - IdentifierInfo *Platform, - bool Implicit, - VersionTuple Introduced, - VersionTuple Deprecated, - VersionTuple Obsoleted, - bool IsUnavailable, - StringRef Message, - bool IsStrict, - StringRef Replacement, - AvailabilityMergeKind AMK, - unsigned AttrSpellingListIndex) { +AvailabilityAttr *Sema::mergeAvailabilityAttr( + NamedDecl *D, SourceRange Range, IdentifierInfo *Platform, bool Implicit, + VersionTuple Introduced, VersionTuple Deprecated, VersionTuple Obsoleted, + bool IsUnavailable, StringRef Message, bool IsStrict, StringRef Replacement, + AvailabilityMergeKind AMK, int Priority, unsigned AttrSpellingListIndex) { VersionTuple MergedIntroduced = Introduced; VersionTuple MergedDeprecated = Deprecated; VersionTuple MergedObsoleted = Obsoleted; @@ -2329,16 +2322,15 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, } // If there is an existing availability attribute for this platform that - // is explicit and the new one is implicit use the explicit one and - // discard the new implicit attribute. - if (!OldAA->isImplicit() && Implicit) { + // has a lower priority use the existing one and discard the new + // attribute. + if (OldAA->getPriority() < Priority) return nullptr; - } - // If there is an existing attribute for this platform that is implicit - // and the new attribute is explicit then erase the old one and - // continue processing the attributes. - if (!Implicit && OldAA->isImplicit()) { + // If there is an existing attribute for this platform that has a higher + // priority than the new attribute then erase the old one and continue + // processing the attributes. + if (OldAA->getPriority() > Priority) { Attrs.erase(Attrs.begin() + i); --e; continue; @@ -2437,11 +2429,10 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, if (!checkAvailabilityAttr(*this, Range, Platform, MergedIntroduced, MergedDeprecated, MergedObsoleted) && !OverrideOrImpl) { - auto *Avail = ::new (Context) AvailabilityAttr(Range, Context, Platform, - Introduced, Deprecated, - Obsoleted, IsUnavailable, Message, - IsStrict, Replacement, - AttrSpellingListIndex); + auto *Avail = ::new (Context) + AvailabilityAttr(Range, Context, Platform, Introduced, Deprecated, + Obsoleted, IsUnavailable, Message, IsStrict, + Replacement, Priority, AttrSpellingListIndex); Avail->setImplicit(Implicit); return Avail; } @@ -2484,15 +2475,13 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } - AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, AL.getRange(), II, - false/*Implicit*/, - Introduced.Version, - Deprecated.Version, - Obsoleted.Version, - IsUnavailable, Str, - IsStrict, Replacement, - Sema::AMK_None, - Index); + int PriorityModifier = AL.isPragmaClangAttribute() + ? Sema::AP_PragmaClangAttribute + : Sema::AP_Explicit; + AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( + ND, AL.getRange(), II, false /*Implicit*/, Introduced.Version, + Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, IsStrict, + Replacement, Sema::AMK_None, PriorityModifier, Index); if (NewAttr) D->addAttr(NewAttr); @@ -2519,6 +2508,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { else return VersionTuple(NewMajor, Version.getMinor().getValue()); } + return VersionTuple(NewMajor); } return VersionTuple(2, 0); @@ -2528,18 +2518,11 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { auto NewDeprecated = adjustWatchOSVersion(Deprecated.Version); auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version); - AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, - AL.getRange(), - NewII, - true/*Implicit*/, - NewIntroduced, - NewDeprecated, - NewObsoleted, - IsUnavailable, Str, - IsStrict, - Replacement, - Sema::AMK_None, - Index); + AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( + ND, AL.getRange(), NewII, true /*Implicit*/, NewIntroduced, + NewDeprecated, NewObsoleted, IsUnavailable, Str, IsStrict, + Replacement, Sema::AMK_None, + PriorityModifier + Sema::AP_InferredFromOtherPlatform, Index); if (NewAttr) D->addAttr(NewAttr); } @@ -2553,20 +2536,13 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { NewII = &S.Context.Idents.get("tvos_app_extension"); if (NewII) { - AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, - AL.getRange(), - NewII, - true/*Implicit*/, - Introduced.Version, - Deprecated.Version, - Obsoleted.Version, - IsUnavailable, Str, - IsStrict, - Replacement, - Sema::AMK_None, - Index); - if (NewAttr) - D->addAttr(NewAttr); + AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( + ND, AL.getRange(), NewII, true /*Implicit*/, Introduced.Version, + Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, IsStrict, + Replacement, Sema::AMK_None, + PriorityModifier + Sema::AP_InferredFromOtherPlatform, Index); + if (NewAttr) + D->addAttr(NewAttr); } } } @@ -3325,7 +3301,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } if (prioritynum < 101 || prioritynum > 65535) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_outof_range) + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_range) << E->getSourceRange() << AL << 101 << 65535; AL.setInvalid(); return; @@ -3480,6 +3456,146 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(NewAttr); } +/// Handle __attribute__((callback(CalleeIdx, PayloadIdx0, ...))) attributes. +static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // The index that identifies the callback callee is mandatory. + if (AL.getNumArgs() == 0) { + S.Diag(AL.getLoc(), diag::err_callback_attribute_no_callee) + << AL.getRange(); + return; + } + + bool HasImplicitThisParam = isInstanceMethod(D); + int32_t NumArgs = getFunctionOrMethodNumParams(D); + + FunctionDecl *FD = D->getAsFunction(); + assert(FD && "Expected a function declaration!"); + + llvm::StringMap<int> NameIdxMapping; + NameIdxMapping["__"] = -1; + + NameIdxMapping["this"] = 0; + + int Idx = 1; + for (const ParmVarDecl *PVD : FD->parameters()) + NameIdxMapping[PVD->getName()] = Idx++; + + auto UnknownName = NameIdxMapping.end(); + + SmallVector<int, 8> EncodingIndices; + for (unsigned I = 0, E = AL.getNumArgs(); I < E; ++I) { + SourceRange SR; + int32_t ArgIdx; + + if (AL.isArgIdent(I)) { + IdentifierLoc *IdLoc = AL.getArgAsIdent(I); + auto It = NameIdxMapping.find(IdLoc->Ident->getName()); + if (It == UnknownName) { + S.Diag(AL.getLoc(), diag::err_callback_attribute_argument_unknown) + << IdLoc->Ident << IdLoc->Loc; + return; + } + + SR = SourceRange(IdLoc->Loc); + ArgIdx = It->second; + } else if (AL.isArgExpr(I)) { + Expr *IdxExpr = AL.getArgAsExpr(I); + + // If the expression is not parseable as an int32_t we have a problem. + if (!checkUInt32Argument(S, AL, IdxExpr, (uint32_t &)ArgIdx, I + 1, + false)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL << (I + 1) << IdxExpr->getSourceRange(); + return; + } + + // Check oob, excluding the special values, 0 and -1. + if (ArgIdx < -1 || ArgIdx > NumArgs) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL << (I + 1) << IdxExpr->getSourceRange(); + return; + } + + SR = IdxExpr->getSourceRange(); + } else { + llvm_unreachable("Unexpected ParsedAttr argument type!"); + } + + if (ArgIdx == 0 && !HasImplicitThisParam) { + S.Diag(AL.getLoc(), diag::err_callback_implicit_this_not_available) + << (I + 1) << SR; + return; + } + + // Adjust for the case we do not have an implicit "this" parameter. In this + // case we decrease all positive values by 1 to get LLVM argument indices. + if (!HasImplicitThisParam && ArgIdx > 0) + ArgIdx -= 1; + + EncodingIndices.push_back(ArgIdx); + } + + int CalleeIdx = EncodingIndices.front(); + // Check if the callee index is proper, thus not "this" and not "unknown". + // This means the "CalleeIdx" has to be non-negative if "HasImplicitThisParam" + // is false and positive if "HasImplicitThisParam" is true. + if (CalleeIdx < (int)HasImplicitThisParam) { + S.Diag(AL.getLoc(), diag::err_callback_attribute_invalid_callee) + << AL.getRange(); + return; + } + + // Get the callee type, note the index adjustment as the AST doesn't contain + // the this type (which the callee cannot reference anyway!). + const Type *CalleeType = + getFunctionOrMethodParamType(D, CalleeIdx - HasImplicitThisParam) + .getTypePtr(); + if (!CalleeType || !CalleeType->isFunctionPointerType()) { + S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type) + << AL.getRange(); + return; + } + + const Type *CalleeFnType = + CalleeType->getPointeeType()->getUnqualifiedDesugaredType(); + + // TODO: Check the type of the callee arguments. + + const auto *CalleeFnProtoType = dyn_cast<FunctionProtoType>(CalleeFnType); + if (!CalleeFnProtoType) { + S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type) + << AL.getRange(); + return; + } + + if (CalleeFnProtoType->getNumParams() > EncodingIndices.size() - 1) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) + << AL << (unsigned)(EncodingIndices.size() - 1); + return; + } + + if (CalleeFnProtoType->getNumParams() < EncodingIndices.size() - 1) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) + << AL << (unsigned)(EncodingIndices.size() - 1); + return; + } + + if (CalleeFnProtoType->isVariadic()) { + S.Diag(AL.getLoc(), diag::err_callback_callee_is_variadic) << AL.getRange(); + return; + } + + // Do not allow multiple callback attributes. + if (D->hasAttr<CallbackAttr>()) { + S.Diag(AL.getLoc(), diag::err_callback_attribute_multiple) << AL.getRange(); + return; + } + + D->addAttr(::new (S.Context) CallbackAttr( + AL.getRange(), S.Context, EncodingIndices.data(), EncodingIndices.size(), + AL.getAttributeSpellingListIndex())); +} + static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Try to find the underlying union declaration. RecordDecl *RD = nullptr; @@ -4157,6 +4273,15 @@ MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range, return ::new (Context) MinSizeAttr(Range, Context, AttrSpellingListIndex); } +NoSpeculativeLoadHardeningAttr *Sema::mergeNoSpeculativeLoadHardeningAttr( + Decl *D, const NoSpeculativeLoadHardeningAttr &AL) { + if (checkAttrMutualExclusion<SpeculativeLoadHardeningAttr>(*this, D, AL)) + return nullptr; + + return ::new (Context) NoSpeculativeLoadHardeningAttr( + AL.getRange(), Context, AL.getSpellingListIndex()); +} + OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex) { if (AlwaysInlineAttr *Inline = D->getAttr<AlwaysInlineAttr>()) { @@ -4177,6 +4302,15 @@ OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range, AttrSpellingListIndex); } +SpeculativeLoadHardeningAttr *Sema::mergeSpeculativeLoadHardeningAttr( + Decl *D, const SpeculativeLoadHardeningAttr &AL) { + if (checkAttrMutualExclusion<NoSpeculativeLoadHardeningAttr>(*this, D, AL)) + return nullptr; + + return ::new (Context) SpeculativeLoadHardeningAttr( + AL.getRange(), Context, AL.getSpellingListIndex()); +} + static void handleAlwaysInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, AL)) return; @@ -4482,11 +4616,44 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, default: llvm_unreachable("unexpected attribute kind"); } + TargetInfo::CallingConvCheckResult A = TargetInfo::CCCR_OK; const TargetInfo &TI = Context.getTargetInfo(); - TargetInfo::CallingConvCheckResult A = TI.checkCallingConvention(CC); + // CUDA functions may have host and/or device attributes which indicate + // their targeted execution environment, therefore the calling convention + // of functions in CUDA should be checked against the target deduced based + // on their host/device attributes. + if (LangOpts.CUDA) { + auto *Aux = Context.getAuxTargetInfo(); + auto CudaTarget = IdentifyCUDATarget(FD); + bool CheckHost = false, CheckDevice = false; + switch (CudaTarget) { + case CFT_HostDevice: + CheckHost = true; + CheckDevice = true; + break; + case CFT_Host: + CheckHost = true; + break; + case CFT_Device: + case CFT_Global: + CheckDevice = true; + break; + case CFT_InvalidTarget: + llvm_unreachable("unexpected cuda target"); + } + auto *HostTI = LangOpts.CUDAIsDevice ? Aux : &TI; + auto *DeviceTI = LangOpts.CUDAIsDevice ? &TI : Aux; + if (CheckHost && HostTI) + A = HostTI->checkCallingConvention(CC); + if (A == TargetInfo::CCCR_OK && CheckDevice && DeviceTI) + A = DeviceTI->checkCallingConvention(CC); + } else { + A = TI.checkCallingConvention(CC); + } if (A != TargetInfo::CCCR_OK) { if (A == TargetInfo::CCCR_Warning) - Diag(Attrs.getLoc(), diag::warn_cconv_ignored) << Attrs; + Diag(Attrs.getLoc(), diag::warn_cconv_ignored) + << Attrs << (int)CallingConventionIgnoredReason::ForThisTarget; // This convention is not valid for the target. Use the default function or // method calling convention. @@ -5116,11 +5283,22 @@ static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D, static void handleObjCDesignatedInitializer(Sema &S, Decl *D, const ParsedAttr &AL) { + DeclContext *Ctx = D->getDeclContext(); + + // This attribute can only be applied to methods in interfaces or class + // extensions. + if (!isa<ObjCInterfaceDecl>(Ctx) && + !(isa<ObjCCategoryDecl>(Ctx) && + cast<ObjCCategoryDecl>(Ctx)->IsClassExtension())) { + S.Diag(D->getLocation(), diag::err_designated_init_attr_non_init); + return; + } + ObjCInterfaceDecl *IFace; - if (auto *CatDecl = dyn_cast<ObjCCategoryDecl>(D->getDeclContext())) + if (auto *CatDecl = dyn_cast<ObjCCategoryDecl>(Ctx)) IFace = CatDecl->getClassInterface(); else - IFace = cast<ObjCInterfaceDecl>(D->getDeclContext()); + IFace = cast<ObjCInterfaceDecl>(Ctx); if (!IFace) return; @@ -5377,6 +5555,27 @@ static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // MSP430 'interrupt' attribute is applied to + // a function with no parameters and void return type. + if (!isFunctionOrMethod(D)) { + S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << "'interrupt'" << 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 (!checkAttributeNumArgs(S, AL, 1)) return; @@ -5386,8 +5585,6 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - // FIXME: Check for decl - it should be void ()(void). - Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0)); llvm::APSInt NumParams(32); if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { @@ -5396,9 +5593,9 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { << NumParamsExpr->getSourceRange(); return; } - + // The argument should be in range 0..63. unsigned Num = NumParams.getLimitedValue(255); - if ((Num & 1) || Num > 30) { + if (Num > 63) { S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) << AL << (int)NumParams.getSExtValue() << NumParamsExpr->getSourceRange(); @@ -5442,14 +5639,14 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) { - S.Diag(D->getLocation(), diag::warn_mips_interrupt_attribute) - << 0; + S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) + << /*MIPS*/ 0 << 0; return; } if (!getFunctionOrMethodResultType(D)->isVoidType()) { - S.Diag(D->getLocation(), diag::warn_mips_interrupt_attribute) - << 1; + S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) + << /*MIPS*/ 0 << 1; return; } @@ -5558,6 +5755,51 @@ static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { handleSimpleAttribute<AVRSignalAttr>(S, D, AL); } +static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!isFunctionOrMethod(D)) { + S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << "'import_module'" << ExpectedFunction; + return; + } + + auto *FD = cast<FunctionDecl>(D); + if (FD->isThisDeclarationADefinition()) { + S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0; + return; + } + + StringRef Str; + SourceLocation ArgLoc; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) + return; + + FD->addAttr(::new (S.Context) WebAssemblyImportModuleAttr( + AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); +} + +static void handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!isFunctionOrMethod(D)) { + S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << "'import_name'" << ExpectedFunction; + return; + } + + auto *FD = cast<FunctionDecl>(D); + if (FD->isThisDeclarationADefinition()) { + S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0; + return; + } + + StringRef Str; + SourceLocation ArgLoc; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) + return; + + FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr( + AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); +} static void handleRISCVInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -5596,12 +5838,14 @@ static void handleRISCVInterruptAttr(Sema &S, Decl *D, } if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) { - S.Diag(D->getLocation(), diag::warn_riscv_interrupt_attribute) << 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_riscv_interrupt_attribute) << 1; + S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) + << /*RISC-V*/ 2 << 1; return; } @@ -5643,57 +5887,115 @@ static void handleInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } -static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { +static bool +checkAMDGPUFlatWorkGroupSizeArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr, + const AMDGPUFlatWorkGroupSizeAttr &Attr) { + // Accept template arguments for now as they depend on something else. + // We'll get to check them when they eventually get instantiated. + if (MinExpr->isValueDependent() || MaxExpr->isValueDependent()) + return false; + uint32_t Min = 0; - Expr *MinExpr = AL.getArgAsExpr(0); - if (!checkUInt32Argument(S, AL, MinExpr, Min)) - return; + if (!checkUInt32Argument(S, Attr, MinExpr, Min, 0)) + return true; uint32_t Max = 0; - Expr *MaxExpr = AL.getArgAsExpr(1); - if (!checkUInt32Argument(S, AL, MaxExpr, Max)) - return; + if (!checkUInt32Argument(S, Attr, MaxExpr, Max, 1)) + return true; if (Min == 0 && Max != 0) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 0; - return; + S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid) + << &Attr << 0; + return true; } if (Min > Max) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 1; - return; + S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid) + << &Attr << 1; + return true; } - D->addAttr(::new (S.Context) - AMDGPUFlatWorkGroupSizeAttr(AL.getLoc(), S.Context, Min, Max, - AL.getAttributeSpellingListIndex())); + return false; } -static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - uint32_t Min = 0; - Expr *MinExpr = AL.getArgAsExpr(0); - if (!checkUInt32Argument(S, AL, MinExpr, Min)) +void Sema::addAMDGPUFlatWorkGroupSizeAttr(SourceRange AttrRange, Decl *D, + Expr *MinExpr, Expr *MaxExpr, + unsigned SpellingListIndex) { + AMDGPUFlatWorkGroupSizeAttr TmpAttr(AttrRange, Context, MinExpr, MaxExpr, + SpellingListIndex); + + if (checkAMDGPUFlatWorkGroupSizeArguments(*this, MinExpr, MaxExpr, TmpAttr)) return; + D->addAttr(::new (Context) AMDGPUFlatWorkGroupSizeAttr( + AttrRange, Context, MinExpr, MaxExpr, SpellingListIndex)); +} + +static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + Expr *MinExpr = AL.getArgAsExpr(0); + Expr *MaxExpr = AL.getArgAsExpr(1); + + S.addAMDGPUFlatWorkGroupSizeAttr(AL.getRange(), D, MinExpr, MaxExpr, + AL.getAttributeSpellingListIndex()); +} + +static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr, + Expr *MaxExpr, + const AMDGPUWavesPerEUAttr &Attr) { + if (S.DiagnoseUnexpandedParameterPack(MinExpr) || + (MaxExpr && S.DiagnoseUnexpandedParameterPack(MaxExpr))) + return true; + + // Accept template arguments for now as they depend on something else. + // We'll get to check them when they eventually get instantiated. + if (MinExpr->isValueDependent() || (MaxExpr && MaxExpr->isValueDependent())) + return false; + + uint32_t Min = 0; + if (!checkUInt32Argument(S, Attr, MinExpr, Min, 0)) + return true; + uint32_t Max = 0; - if (AL.getNumArgs() == 2) { - Expr *MaxExpr = AL.getArgAsExpr(1); - if (!checkUInt32Argument(S, AL, MaxExpr, Max)) - return; - } + if (MaxExpr && !checkUInt32Argument(S, Attr, MaxExpr, Max, 1)) + return true; if (Min == 0 && Max != 0) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 0; - return; + S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid) + << &Attr << 0; + return true; } if (Max != 0 && Min > Max) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 1; - return; + S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid) + << &Attr << 1; + return true; } - D->addAttr(::new (S.Context) - AMDGPUWavesPerEUAttr(AL.getLoc(), S.Context, Min, Max, - AL.getAttributeSpellingListIndex())); + return false; +} + +void Sema::addAMDGPUWavesPerEUAttr(SourceRange AttrRange, Decl *D, + Expr *MinExpr, Expr *MaxExpr, + unsigned SpellingListIndex) { + AMDGPUWavesPerEUAttr TmpAttr(AttrRange, Context, MinExpr, MaxExpr, + SpellingListIndex); + + if (checkAMDGPUWavesPerEUArguments(*this, MinExpr, MaxExpr, TmpAttr)) + return; + + D->addAttr(::new (Context) AMDGPUWavesPerEUAttr(AttrRange, Context, MinExpr, + MaxExpr, SpellingListIndex)); +} + +static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1) || + !checkAttributeAtMostNumArgs(S, AL, 2)) + return; + + Expr *MinExpr = AL.getArgAsExpr(0); + Expr *MaxExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr; + + S.addAMDGPUWavesPerEUAttr(AL.getRange(), D, MinExpr, MaxExpr, + AL.getAttributeSpellingListIndex()); } static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -6001,7 +6303,8 @@ static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.checkStringLiteralArgumentAttr(AL, I, SanitizerName, &LiteralLoc)) return; - if (parseSanitizerValue(SanitizerName, /*AllowGroups=*/true) == 0) + if (parseSanitizerValue(SanitizerName, /*AllowGroups=*/true) == + SanitizerMask()) S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName; else if (isGlobalVar(D) && SanitizerName != "address") S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) @@ -6114,7 +6417,9 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (const auto *PDecl = dyn_cast<ParmVarDecl>(D)) { const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr(); if (AL.getName()->getName().find("read_write") != StringRef::npos) { - if (S.getLangOpts().OpenCLVersion < 200 || DeclTy->isPipeType()) { + if ((!S.getLangOpts().OpenCLCPlusPlus && + S.getLangOpts().OpenCLVersion < 200) || + DeclTy->isPipeType()) { S.Diag(AL.getLoc(), diag::err_opencl_invalid_read_write) << AL << PDecl->getType() << DeclTy->isImageType(); D->setInvalidDecl(true); @@ -6221,6 +6526,42 @@ static void handleObjCExternallyRetainedAttr(Sema &S, Decl *D, handleSimpleAttribute<ObjCExternallyRetainedAttr>(S, D, AL); } +static void handleMIGServerRoutineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // Check that the return type is a `typedef int kern_return_t` or a typedef + // around it, because otherwise MIG convention checks make no sense. + // BlockDecl doesn't store a return type, so it's annoying to check, + // so let's skip it for now. + if (!isa<BlockDecl>(D)) { + QualType T = getFunctionOrMethodResultType(D); + bool IsKernReturnT = false; + while (const auto *TT = T->getAs<TypedefType>()) { + IsKernReturnT = (TT->getDecl()->getName() == "kern_return_t"); + T = TT->desugar(); + } + if (!IsKernReturnT || T.getCanonicalType() != S.getASTContext().IntTy) { + S.Diag(D->getBeginLoc(), + diag::warn_mig_server_routine_does_not_return_kern_return_t); + return; + } + } + + handleSimpleAttribute<MIGServerRoutineAttr>(S, D, AL); +} + +static void handleMSAllocatorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // Warn if the return type is not a pointer or reference type. + if (auto *FD = dyn_cast<FunctionDecl>(D)) { + QualType RetTy = FD->getReturnType(); + if (!RetTy->isPointerType() && !RetTy->isReferenceType()) { + S.Diag(AL.getLoc(), diag::warn_declspec_allocator_nonpointer) + << AL.getRange() << RetTy; + return; + } + } + + handleSimpleAttribute<MSAllocatorAttr>(S, D, AL); +} + //===----------------------------------------------------------------------===// // Top Level Sema Entry Points //===----------------------------------------------------------------------===// @@ -6311,6 +6652,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_AVRSignal: handleAVRSignalAttr(S, D, AL); break; + case ParsedAttr::AT_WebAssemblyImportModule: + handleWebAssemblyImportModuleAttr(S, D, AL); + break; + case ParsedAttr::AT_WebAssemblyImportName: + handleWebAssemblyImportNameAttr(S, D, AL); + break; case ParsedAttr::AT_IBAction: handleSimpleAttribute<IBActionAttr>(S, D, AL); break; @@ -6414,6 +6761,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_FormatArg: handleFormatArgAttr(S, D, AL); break; + case ParsedAttr::AT_Callback: + handleCallbackAttr(S, D, AL); + break; case ParsedAttr::AT_CUDAGlobal: handleGlobalAttr(S, D, AL); break; @@ -6599,7 +6949,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleSectionAttr(S, D, AL); break; case ParsedAttr::AT_SpeculativeLoadHardening: - handleSimpleAttribute<SpeculativeLoadHardeningAttr>(S, D, AL); + handleSimpleAttributeWithExclusions<SpeculativeLoadHardeningAttr, + NoSpeculativeLoadHardeningAttr>(S, D, + AL); + break; + case ParsedAttr::AT_NoSpeculativeLoadHardening: + handleSimpleAttributeWithExclusions<NoSpeculativeLoadHardeningAttr, + SpeculativeLoadHardeningAttr>(S, D, AL); break; case ParsedAttr::AT_CodeSeg: handleCodeSegAttr(S, D, AL); @@ -6619,6 +6975,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_ObjCRootClass: handleSimpleAttribute<ObjCRootClassAttr>(S, D, AL); break; + case ParsedAttr::AT_ObjCNonLazyClass: + handleSimpleAttribute<ObjCNonLazyClassAttr>(S, D, AL); + break; case ParsedAttr::AT_ObjCSubclassingRestricted: handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, AL); break; @@ -6932,6 +7291,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_ObjCExternallyRetained: handleObjCExternallyRetainedAttr(S, D, AL); break; + + case ParsedAttr::AT_MIGServerRoutine: + handleMIGServerRoutineAttr(S, D, AL); + break; + + case ParsedAttr::AT_MSAllocator: + handleMSAllocatorAttr(S, D, AL); + break; } } @@ -6997,6 +7364,17 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, } } } + + // Do this check after processing D's attributes because the attribute + // objc_method_family can change whether the given method is in the init + // family, and it can be applied after objc_designated_initializer. This is a + // bit of a hack, but we need it to be compatible with versions of clang that + // processed the attribute list in the wrong order. + if (D->hasAttr<ObjCDesignatedInitializerAttr>() && + cast<ObjCMethodDecl>(D)->getMethodFamily() != OMF_init) { + Diag(D->getLocation(), diag::err_designated_init_attr_non_init); + D->dropAttr<ObjCDesignatedInitializerAttr>(); + } } // Helper for delayed processing TransparentUnion attribute. @@ -7346,13 +7724,11 @@ ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, return true; } else if (K == AR_Unavailable) { // It is perfectly fine to refer to an 'unavailable' Objective-C method - // when it's actually defined and is referenced from within the - // @implementation itself. In this context, we interpret unavailable as a - // form of access control. + // when it is referenced from within the @implementation itself. In this + // context, we interpret unavailable as a form of access control. if (const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) { if (const auto *Impl = dyn_cast<ObjCImplDecl>(C)) { - if (MD->getClassInterface() == Impl->getClassInterface() && - MD->isDefined()) + if (MD->getClassInterface() == Impl->getClassInterface()) return true; } } |