diff options
Diffstat (limited to 'gnu/llvm/tools/clang/lib')
-rw-r--r-- | gnu/llvm/tools/clang/lib/Analysis/FormatString.cpp | 10 | ||||
-rw-r--r-- | gnu/llvm/tools/clang/lib/Basic/Targets.cpp | 22 | ||||
-rw-r--r-- | gnu/llvm/tools/clang/lib/CodeGen/CGCall.cpp | 533 | ||||
-rw-r--r-- | gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.cpp | 6 | ||||
-rw-r--r-- | gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.cpp | 22 | ||||
-rw-r--r-- | gnu/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp | 715 | ||||
-rw-r--r-- | gnu/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp | 649 | ||||
-rw-r--r-- | gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.cpp | 54 | ||||
-rw-r--r-- | gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.h | 6 | ||||
-rw-r--r-- | gnu/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp | 576 | ||||
-rw-r--r-- | gnu/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp | 94 | ||||
-rw-r--r-- | gnu/llvm/tools/clang/lib/Sema/SemaChecking.cpp | 2699 | ||||
-rw-r--r-- | gnu/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp | 4363 |
13 files changed, 5871 insertions, 3878 deletions
diff --git a/gnu/llvm/tools/clang/lib/Analysis/FormatString.cpp b/gnu/llvm/tools/clang/lib/Analysis/FormatString.cpp index 7e8930c964a..f2ebc52274d 100644 --- a/gnu/llvm/tools/clang/lib/Analysis/FormatString.cpp +++ b/gnu/llvm/tools/clang/lib/Analysis/FormatString.cpp @@ -407,7 +407,7 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { case WIntTy: { - QualType PromoArg = + QualType PromoArg = argTy->isPromotableIntegerType() ? C.getPromotedIntegerType(argTy) : argTy; @@ -623,7 +623,7 @@ const char *ConversionSpecifier::toString() const { Optional<ConversionSpecifier> ConversionSpecifier::getStandardSpecifier() const { ConversionSpecifier::Kind NewKind; - + switch (getKind()) { default: return None; @@ -672,7 +672,7 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const { switch (LM.getKind()) { case LengthModifier::None: return true; - + // Handle most integer flags case LengthModifier::AsShort: if (Target.getTriple().isOSMSVCRT()) { @@ -716,7 +716,7 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const { default: return false; } - + // Handle 'l' flag case LengthModifier::AsLong: // or AsWideChar switch (CS.getKind()) { @@ -753,7 +753,7 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const { default: return false; } - + case LengthModifier::AsLongDouble: switch (CS.getKind()) { case ConversionSpecifier::aArg: diff --git a/gnu/llvm/tools/clang/lib/Basic/Targets.cpp b/gnu/llvm/tools/clang/lib/Basic/Targets.cpp index 7deebc06c3e..1ef2fe3b814 100644 --- a/gnu/llvm/tools/clang/lib/Basic/Targets.cpp +++ b/gnu/llvm/tools/clang/lib/Basic/Targets.cpp @@ -29,6 +29,7 @@ #include "Targets/OSTargets.h" #include "Targets/PNaCl.h" #include "Targets/PPC.h" +#include "Targets/RISCV.h" #include "Targets/SPIR.h" #include "Targets/Sparc.h" #include "Targets/SystemZ.h" @@ -37,6 +38,7 @@ #include "Targets/X86.h" #include "Targets/XCore.h" #include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" using namespace clang; @@ -370,6 +372,17 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, case llvm::Triple::r600: return new AMDGPUTargetInfo(Triple, Opts); + case llvm::Triple::riscv32: + // TODO: add cases for FreeBSD, NetBSD, RTEMS once tested. + if (os == llvm::Triple::Linux) + return new LinuxTargetInfo<RISCV32TargetInfo>(Triple, Opts); + return new RISCV32TargetInfo(Triple, Opts); + case llvm::Triple::riscv64: + // TODO: add cases for FreeBSD, NetBSD, RTEMS once tested. + if (os == llvm::Triple::Linux) + return new LinuxTargetInfo<RISCV64TargetInfo>(Triple, Opts); + return new RISCV64TargetInfo(Triple, Opts); + case llvm::Triple::sparc: switch (os) { case llvm::Triple::Linux: @@ -595,6 +608,10 @@ TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, // Set the target CPU if specified. if (!Opts->CPU.empty() && !Target->setCPU(Opts->CPU)) { Diags.Report(diag::err_target_unknown_cpu) << Opts->CPU; + SmallVector<StringRef, 32> ValidList; + Target->fillValidCPUList(ValidList); + if (!ValidList.empty()) + Diags.Report(diag::note_valid_options) << llvm::join(ValidList, ", "); return nullptr; } @@ -621,6 +638,9 @@ TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, Opts->Features.clear(); for (const auto &F : Features) Opts->Features.push_back((F.getValue() ? "+" : "-") + F.getKey().str()); + // Sort here, so we handle the features in a predictable order. (This matters + // when we're dealing with features that overlap.) + llvm::sort(Opts->Features.begin(), Opts->Features.end()); if (!Target->handleTargetFeatures(Opts->Features, Diags)) return nullptr; @@ -632,5 +652,7 @@ TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, if (!Target->validateTarget(Diags)) return nullptr; + Target->CheckFixedPointBits(); + return Target.release(); } diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGCall.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGCall.cpp index de67ee39c14..6fe84a07e38 100644 --- a/gnu/llvm/tools/clang/lib/CodeGen/CGCall.cpp +++ b/gnu/llvm/tools/clang/lib/CodeGen/CGCall.cpp @@ -29,15 +29,15 @@ #include "clang/CodeGen/SwiftCallingConv.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Transforms/Utils/Local.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Attributes.h" -#include "llvm/IR/CallingConv.h" #include "llvm/IR/CallSite.h" +#include "llvm/IR/CallingConv.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" -#include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicInst.h" -#include "llvm/Transforms/Utils/Local.h" +#include "llvm/IR/Intrinsics.h" using namespace clang; using namespace CodeGen; @@ -255,6 +255,16 @@ CodeGenTypes::arrangeCXXMethodType(const CXXRecordDecl *RD, FTP->getCanonicalTypeUnqualified().getAs<FunctionProtoType>(), MD); } +/// Set calling convention for CUDA/HIP kernel. +static void setCUDAKernelCallingConvention(CanQualType &FTy, CodeGenModule &CGM, + const FunctionDecl *FD) { + if (FD->hasAttr<CUDAGlobalAttr>()) { + const FunctionType *FT = FTy->getAs<FunctionType>(); + CGM.getTargetCodeGenInfo().setCUDAKernelCallingConvention(FT); + FTy = FT->getCanonicalTypeUnqualified(); + } +} + /// Arrange the argument and result information for a declaration or /// definition of the given C++ non-static member function. The /// member function must be an ordinary function, i.e. not a @@ -264,7 +274,9 @@ CodeGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *MD) { assert(!isa<CXXConstructorDecl>(MD) && "wrong method for constructors!"); assert(!isa<CXXDestructorDecl>(MD) && "wrong method for destructors!"); - CanQual<FunctionProtoType> prototype = GetFormalType(MD); + CanQualType FT = GetFormalType(MD).getAs<Type>(); + setCUDAKernelCallingConvention(FT, CGM, MD); + auto prototype = FT.getAs<FunctionProtoType>(); if (MD->isInstance()) { // The abstract case is perfectly fine. @@ -424,6 +436,7 @@ CodeGenTypes::arrangeFunctionDeclaration(const FunctionDecl *FD) { CanQualType FTy = FD->getType()->getCanonicalTypeUnqualified(); assert(isa<FunctionType>(FTy)); + setCUDAKernelCallingConvention(FTy, CGM, FD); // When declaring a function without a prototype, always use a // non-variadic type. @@ -513,8 +526,8 @@ CodeGenTypes::arrangeGlobalDeclaration(GlobalDecl GD) { /// correct type, and the caller will bitcast the function to the correct /// prototype. const CGFunctionInfo & -CodeGenTypes::arrangeMSMemberPointerThunk(const CXXMethodDecl *MD) { - assert(MD->isVirtual() && "only virtual memptrs have thunks"); +CodeGenTypes::arrangeUnprototypedMustTailThunk(const CXXMethodDecl *MD) { + assert(MD->isVirtual() && "only methods have thunks"); CanQual<FunctionProtoType> FTP = GetFormalType(MD); CanQualType ArgTys[] = { GetThisType(Context, MD->getParent()) }; return arrangeLLVMFunctionInfo(Context.VoidTy, /*instanceMethod=*/false, @@ -776,7 +789,7 @@ CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType, bool erased = FunctionsBeingProcessed.erase(FI); (void)erased; assert(erased && "Not in set?"); - + return *FI; } @@ -803,6 +816,7 @@ CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC, FI->NoReturn = info.getNoReturn(); FI->ReturnsRetained = info.getProducesResult(); FI->NoCallerSavedRegs = info.getNoCallerSavedRegs(); + FI->NoCfCheck = info.getNoCfCheck(); FI->Required = required; FI->HasRegParm = info.getHasRegParm(); FI->RegParm = info.getRegParm(); @@ -904,8 +918,7 @@ getTypeExpansion(QualType Ty, const ASTContext &Context) { CharUnits UnionSize = CharUnits::Zero(); for (const auto *FD : RD->fields()) { - // Skip zero length bitfields. - if (FD->isBitField() && FD->getBitWidthValue(Context) == 0) + if (FD->isZeroLengthBitField(Context)) continue; assert(!FD->isBitField() && "Cannot expand structure with bit-field members."); @@ -926,8 +939,7 @@ getTypeExpansion(QualType Ty, const ASTContext &Context) { } for (const auto *FD : RD->fields()) { - // Skip zero length bitfields. - if (FD->isBitField() && FD->getBitWidthValue(Context) == 0) + if (FD->isZeroLengthBitField(Context)) continue; assert(!FD->isBitField() && "Cannot expand structure with bit-field members."); @@ -1040,42 +1052,49 @@ void CodeGenFunction::ExpandTypeFromArgs( } void CodeGenFunction::ExpandTypeToArgs( - QualType Ty, RValue RV, llvm::FunctionType *IRFuncTy, + QualType Ty, CallArg Arg, llvm::FunctionType *IRFuncTy, SmallVectorImpl<llvm::Value *> &IRCallArgs, unsigned &IRCallArgPos) { auto Exp = getTypeExpansion(Ty, getContext()); if (auto CAExp = dyn_cast<ConstantArrayExpansion>(Exp.get())) { - forConstantArrayExpansion(*this, CAExp, RV.getAggregateAddress(), - [&](Address EltAddr) { - RValue EltRV = - convertTempToRValue(EltAddr, CAExp->EltTy, SourceLocation()); - ExpandTypeToArgs(CAExp->EltTy, EltRV, IRFuncTy, IRCallArgs, IRCallArgPos); - }); + Address Addr = Arg.hasLValue() ? Arg.getKnownLValue().getAddress() + : Arg.getKnownRValue().getAggregateAddress(); + forConstantArrayExpansion( + *this, CAExp, Addr, [&](Address EltAddr) { + CallArg EltArg = CallArg( + convertTempToRValue(EltAddr, CAExp->EltTy, SourceLocation()), + CAExp->EltTy); + ExpandTypeToArgs(CAExp->EltTy, EltArg, IRFuncTy, IRCallArgs, + IRCallArgPos); + }); } else if (auto RExp = dyn_cast<RecordExpansion>(Exp.get())) { - Address This = RV.getAggregateAddress(); + Address This = Arg.hasLValue() ? Arg.getKnownLValue().getAddress() + : Arg.getKnownRValue().getAggregateAddress(); for (const CXXBaseSpecifier *BS : RExp->Bases) { // Perform a single step derived-to-base conversion. Address Base = GetAddressOfBaseClass(This, Ty->getAsCXXRecordDecl(), &BS, &BS + 1, /*NullCheckValue=*/false, SourceLocation()); - RValue BaseRV = RValue::getAggregate(Base); + CallArg BaseArg = CallArg(RValue::getAggregate(Base), BS->getType()); // Recurse onto bases. - ExpandTypeToArgs(BS->getType(), BaseRV, IRFuncTy, IRCallArgs, + ExpandTypeToArgs(BS->getType(), BaseArg, IRFuncTy, IRCallArgs, IRCallArgPos); } LValue LV = MakeAddrLValue(This, Ty); for (auto FD : RExp->Fields) { - RValue FldRV = EmitRValueForField(LV, FD, SourceLocation()); - ExpandTypeToArgs(FD->getType(), FldRV, IRFuncTy, IRCallArgs, + CallArg FldArg = + CallArg(EmitRValueForField(LV, FD, SourceLocation()), FD->getType()); + ExpandTypeToArgs(FD->getType(), FldArg, IRFuncTy, IRCallArgs, IRCallArgPos); } } else if (isa<ComplexExpansion>(Exp.get())) { - ComplexPairTy CV = RV.getComplexVal(); + ComplexPairTy CV = Arg.getKnownRValue().getComplexVal(); IRCallArgs[IRCallArgPos++] = CV.first; IRCallArgs[IRCallArgPos++] = CV.second; } else { assert(isa<NoExpansion>(Exp.get())); + auto RV = Arg.getKnownRValue(); assert(RV.isScalar() && "Unexpected non-scalar rvalue during struct expansion."); @@ -1325,7 +1344,7 @@ static void CreateCoercedStore(llvm::Value *Src, } static Address emitAddressAtOffset(CodeGenFunction &CGF, Address addr, - const ABIArgInfo &info) { + const ABIArgInfo &info) { if (unsigned offset = info.getDirectOffset()) { addr = CGF.Builder.CreateElementBitCast(addr, CGF.Int8Ty); addr = CGF.Builder.CreateConstInBoundsByteGEP(addr, @@ -1479,7 +1498,8 @@ void ClangToLLVMArgMapping::construct(const ASTContext &Context, /***/ bool CodeGenModule::ReturnTypeUsesSRet(const CGFunctionInfo &FI) { - return FI.getReturnInfo().isIndirect(); + const auto &RI = FI.getReturnInfo(); + return RI.isIndirect() || (RI.isInAlloca() && RI.getInAllocaSRet()); } bool CodeGenModule::ReturnSlotInterferesWithArgs(const CGFunctionInfo &FI) { @@ -1655,7 +1675,7 @@ llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) { if (!isFuncTypeConvertible(FPT)) return llvm::StructType::get(getLLVMContext()); - + const CGFunctionInfo *Info; if (isa<CXXDestructorDecl>(MD)) Info = @@ -1672,7 +1692,7 @@ static void AddAttributesFromFunctionProtoType(ASTContext &Ctx, return; if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) && - FPT->isNothrow(Ctx)) + FPT->isNothrow()) FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); } @@ -1714,12 +1734,19 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone, FuncAttrs.addAttribute("less-precise-fpmad", llvm::toStringRef(CodeGenOpts.LessPreciseFPMAD)); + if (CodeGenOpts.NullPointerIsValid) + FuncAttrs.addAttribute("null-pointer-is-valid", "true"); if (!CodeGenOpts.FPDenormalMode.empty()) FuncAttrs.addAttribute("denormal-fp-math", CodeGenOpts.FPDenormalMode); FuncAttrs.addAttribute("no-trapping-math", llvm::toStringRef(CodeGenOpts.NoTrappingMath)); + // Strict (compliant) code is the default, so only add this attribute to + // indicate that we are trying to workaround a problem case. + if (!CodeGenOpts.StrictFloatCastOverflow) + FuncAttrs.addAttribute("strict-float-cast-overflow", "false"); + // TODO: Are these all needed? // unsafe/inf/nan/nsz are handled by instruction-level FastMathFlags. FuncAttrs.addAttribute("no-infs-fp-math", @@ -1738,6 +1765,10 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone, "correctly-rounded-divide-sqrt-fp-math", llvm::toStringRef(CodeGenOpts.CorrectlyRoundedDivSqrt)); + if (getLangOpts().OpenCL) + FuncAttrs.addAttribute("denorms-are-zero", + llvm::toStringRef(CodeGenOpts.FlushDenorm)); + // TODO: Reciprocal estimate codegen options should apply to instructions? const std::vector<std::string> &Recips = CodeGenOpts.Reciprocals; if (!Recips.empty()) @@ -1769,7 +1800,7 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone, FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); // Respect -fcuda-flush-denormals-to-zero. - if (getLangOpts().CUDADeviceFlushDenormalsToZero) + if (CodeGenOpts.FlushDenorm) FuncAttrs.addAttribute("nvptx-f32ftz", "true"); } } @@ -1793,7 +1824,7 @@ void CodeGenModule::ConstructAttributeList( FuncAttrs.addAttribute(llvm::Attribute::NoReturn); // If we have information about the function prototype, we can learn - // attributes form there. + // attributes from there. AddAttributesFromFunctionProtoType(getContext(), FuncAttrs, CalleeInfo.getCalleeFunctionProtoType()); @@ -1838,18 +1869,20 @@ void CodeGenModule::ConstructAttributeList( } if (TargetDecl->hasAttr<RestrictAttr>()) RetAttrs.addAttribute(llvm::Attribute::NoAlias); - if (TargetDecl->hasAttr<ReturnsNonNullAttr>()) + if (TargetDecl->hasAttr<ReturnsNonNullAttr>() && + !CodeGenOpts.NullPointerIsValid) RetAttrs.addAttribute(llvm::Attribute::NonNull); if (TargetDecl->hasAttr<AnyX86NoCallerSavedRegistersAttr>()) FuncAttrs.addAttribute("no_caller_saved_registers"); + if (TargetDecl->hasAttr<AnyX86NoCfCheckAttr>()) + FuncAttrs.addAttribute(llvm::Attribute::NoCfCheck); HasOptnone = TargetDecl->hasAttr<OptimizeNoneAttr>(); if (auto *AllocSize = TargetDecl->getAttr<AllocSizeAttr>()) { Optional<unsigned> NumElemsParam; - // alloc_size args are base-1, 0 means not present. - if (unsigned N = AllocSize->getNumElemsParam()) - NumElemsParam = N - 1; - FuncAttrs.addAllocSizeAttr(AllocSize->getElemSizeParam() - 1, + if (AllocSize->getNumElemsParam().isValid()) + NumElemsParam = AllocSize->getNumElemsParam().getLLVMIndex(); + FuncAttrs.addAllocSizeAttr(AllocSize->getElemSizeParam().getLLVMIndex(), NumElemsParam); } } @@ -1870,56 +1903,42 @@ void CodeGenModule::ConstructAttributeList( } } + if (TargetDecl && TargetDecl->hasAttr<OpenCLKernelAttr>()) { + if (getLangOpts().OpenCLVersion <= 120) { + // OpenCL v1.2 Work groups are always uniform + FuncAttrs.addAttribute("uniform-work-group-size", "true"); + } else { + // OpenCL v2.0 Work groups may be whether uniform or not. + // '-cl-uniform-work-group-size' compile option gets a hint + // to the compiler that the global work-size be a multiple of + // the work-group size specified to clEnqueueNDRangeKernel + // (i.e. work groups are uniform). + FuncAttrs.addAttribute("uniform-work-group-size", + llvm::toStringRef(CodeGenOpts.UniformWGSize)); + } + } + if (!AttrOnCallSite) { - bool DisableTailCalls = - CodeGenOpts.DisableTailCalls || - (TargetDecl && (TargetDecl->hasAttr<DisableTailCallsAttr>() || - TargetDecl->hasAttr<AnyX86InterruptAttr>())); + bool DisableTailCalls = false; + + if (CodeGenOpts.DisableTailCalls) + DisableTailCalls = true; + else if (TargetDecl) { + if (TargetDecl->hasAttr<DisableTailCallsAttr>() || + TargetDecl->hasAttr<AnyX86InterruptAttr>()) + DisableTailCalls = true; + else if (CodeGenOpts.NoEscapingBlockTailCalls) { + if (const auto *BD = dyn_cast<BlockDecl>(TargetDecl)) + if (!BD->doesNotEscape()) + DisableTailCalls = true; + } + } + FuncAttrs.addAttribute("disable-tail-calls", llvm::toStringRef(DisableTailCalls)); - if (CodeGenOpts.ReturnProtector) FuncAttrs.addAttribute("ret-protector"); - - // Add target-cpu and target-features attributes to functions. If - // we have a decl for the function and it has a target attribute then - // parse that and add it to the feature set. - StringRef TargetCPU = getTarget().getTargetOpts().CPU; - std::vector<std::string> Features; - const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl); - if (FD && FD->hasAttr<TargetAttr>()) { - llvm::StringMap<bool> FeatureMap; - getFunctionFeatureMap(FeatureMap, FD); - - // Produce the canonical string for this set of features. - for (llvm::StringMap<bool>::const_iterator it = FeatureMap.begin(), - ie = FeatureMap.end(); - it != ie; ++it) - Features.push_back((it->second ? "+" : "-") + it->first().str()); - - // Now add the target-cpu and target-features to the function. - // While we populated the feature map above, we still need to - // get and parse the target attribute so we can get the cpu for - // the function. - const auto *TD = FD->getAttr<TargetAttr>(); - TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse(); - if (ParsedAttr.Architecture != "" && - getTarget().isValidCPUName(ParsedAttr.Architecture)) - TargetCPU = ParsedAttr.Architecture; - } else { - // Otherwise just add the existing target cpu and target features to the - // function. - Features = getTarget().getTargetOpts().Features; - } - - if (TargetCPU != "") - FuncAttrs.addAttribute("target-cpu", TargetCPU); - if (!Features.empty()) { - std::sort(Features.begin(), Features.end()); - FuncAttrs.addAttribute( - "target-features", - llvm::join(Features, ",")); - } + GetCPUAndFeaturesAttributes(TargetDecl, FuncAttrs); } ClangToLLVMArgMapping IRFunctionArgs(getContext(), FI); @@ -1928,9 +1947,9 @@ void CodeGenModule::ConstructAttributeList( const ABIArgInfo &RetAI = FI.getReturnInfo(); switch (RetAI.getKind()) { case ABIArgInfo::Extend: - if (RetTy->hasSignedIntegerRepresentation()) + if (RetAI.isSignExt()) RetAttrs.addAttribute(llvm::Attribute::SExt); - else if (RetTy->hasUnsignedIntegerRepresentation()) + else RetAttrs.addAttribute(llvm::Attribute::ZExt); LLVM_FALLTHROUGH; case ABIArgInfo::Direct: @@ -1960,7 +1979,8 @@ void CodeGenModule::ConstructAttributeList( if (!PTy->isIncompleteType() && PTy->isConstantSizeType()) RetAttrs.addDereferenceableAttr(getContext().getTypeSizeInChars(PTy) .getQuantity()); - else if (getContext().getTargetAddressSpace(PTy) == 0) + else if (getContext().getTargetAddressSpace(PTy) == 0 && + !CodeGenOpts.NullPointerIsValid) RetAttrs.addAttribute(llvm::Attribute::NonNull); } @@ -1970,7 +1990,8 @@ void CodeGenModule::ConstructAttributeList( // Attach attributes to sret. if (IRFunctionArgs.hasSRetArg()) { llvm::AttrBuilder SRETAttrs; - SRETAttrs.addAttribute(llvm::Attribute::StructRet); + if (!RetAI.getSuppressSRet()) + SRETAttrs.addAttribute(llvm::Attribute::StructRet); hasUsedSRet = true; if (RetAI.getInReg()) SRETAttrs.addAttribute(llvm::Attribute::InReg); @@ -2009,14 +2030,10 @@ void CodeGenModule::ConstructAttributeList( // sense to do it here because parameters are so messed up. switch (AI.getKind()) { case ABIArgInfo::Extend: - if (ParamType->isSignedIntegerOrEnumerationType()) + if (AI.isSignExt()) Attrs.addAttribute(llvm::Attribute::SExt); - else if (ParamType->isUnsignedIntegerOrEnumerationType()) { - if (getTypes().getABIInfo().shouldSignExtUnsignedType(ParamType)) - Attrs.addAttribute(llvm::Attribute::SExt); - else - Attrs.addAttribute(llvm::Attribute::ZExt); - } + else + Attrs.addAttribute(llvm::Attribute::ZExt); LLVM_FALLTHROUGH; case ABIArgInfo::Direct: if (ArgNo == 0 && FI.isChainCall()) @@ -2073,7 +2090,8 @@ void CodeGenModule::ConstructAttributeList( if (!PTy->isIncompleteType() && PTy->isConstantSizeType()) Attrs.addDereferenceableAttr(getContext().getTypeSizeInChars(PTy) .getQuantity()); - else if (getContext().getTargetAddressSpace(PTy) == 0) + else if (getContext().getTargetAddressSpace(PTy) == 0 && + !CodeGenOpts.NullPointerIsValid) Attrs.addAttribute(llvm::Attribute::NonNull); } @@ -2258,11 +2276,16 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i, ++info_it, ++ArgNo) { const VarDecl *Arg = *i; - QualType Ty = info_it->type; const ABIArgInfo &ArgI = info_it->info; bool isPromoted = isa<ParmVarDecl>(Arg) && cast<ParmVarDecl>(Arg)->isKNRPromoted(); + // We are converting from ABIArgInfo type to VarDecl type directly, unless + // the parameter is promoted. In this case we convert to + // CGFunctionInfo::ArgInfo type with subsequent argument demotion. + QualType Ty = isPromoted ? info_it->type : Arg->getType(); + assert(hasScalarEvaluationKind(Ty) == + hasScalarEvaluationKind(Arg->getType())); unsigned FirstIRArg, NumIRArgs; std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo); @@ -2328,7 +2351,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(Arg)) { if (getNonNullAttr(CurCodeDecl, PVD, PVD->getType(), - PVD->getFunctionScopeIndex())) + PVD->getFunctionScopeIndex()) && + !CGM.getCodeGenOpts().NullPointerIsValid) AI->addAttr(llvm::Attribute::NonNull); QualType OTy = PVD->getOriginalType(); @@ -2347,7 +2371,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, Attrs.addDereferenceableAttr( getContext().getTypeSizeInChars(ETy).getQuantity()*ArrSize); AI->addAttrs(Attrs); - } else if (getContext().getTargetAddressSpace(ETy) == 0) { + } else if (getContext().getTargetAddressSpace(ETy) == 0 && + !CGM.getCodeGenOpts().NullPointerIsValid) { AI->addAttr(llvm::Attribute::NonNull); } } @@ -2357,7 +2382,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // we can't use the dereferenceable attribute, but in addrspace(0) // we know that it must be nonnull. if (ArrTy->getSizeModifier() == VariableArrayType::Static && - !getContext().getTargetAddressSpace(ArrTy->getElementType())) + !getContext().getTargetAddressSpace(ArrTy->getElementType()) && + !CGM.getCodeGenOpts().NullPointerIsValid) AI->addAttr(llvm::Attribute::NonNull); } @@ -2659,7 +2685,7 @@ static llvm::Value *tryRemoveRetainOfSelf(CodeGenFunction &CGF, llvm::Value *retainedValue = retainCall->getArgOperand(0); llvm::LoadInst *load = dyn_cast<llvm::LoadInst>(retainedValue->stripPointerCasts()); - if (!load || load->isAtomic() || load->isVolatile() || + if (!load || load->isAtomic() || load->isVolatile() || load->getPointerOperand() != CGF.GetAddrOfLocalVar(self).getPointer()) return nullptr; @@ -3025,7 +3051,8 @@ static AggValueSlot createPlaceholderSlot(CodeGenFunction &CGF, Ty.getQualifiers(), AggValueSlot::IsNotDestructed, AggValueSlot::DoesNotNeedGCBarriers, - AggValueSlot::IsNotAliased); + AggValueSlot::IsNotAliased, + AggValueSlot::DoesNotOverlap); } void CodeGenFunction::EmitDelegateCallArg(CallArgList &args, @@ -3065,6 +3092,19 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args, } else { args.add(convertTempToRValue(local, type, loc), type); } + + // Deactivate the cleanup for the callee-destructed param that was pushed. + if (hasAggregateEvaluationKind(type) && !CurFuncIsThunk && + type->getAs<RecordType>()->getDecl()->isParamDestroyedInCallee() && + type.isDestructedType()) { + EHScopeStack::stable_iterator cleanup = + CalleeDestructedParamCleanups.lookup(cast<ParmVarDecl>(param)); + assert(cleanup.isValid() && + "cleanup for callee-destructed param not recorded"); + // This unreachable is a temporary marker which will be removed later. + llvm::Instruction *isActive = Builder.CreateUnreachable(); + args.addArgCleanupDeactivation(cleanup, isActive); + } } static bool isProvablyNull(llvm::Value *addr) { @@ -3101,7 +3141,7 @@ static void emitWriteback(CodeGenFunction &CGF, // Cast it back, in case we're writing an id to a Foo* or something. value = CGF.Builder.CreateBitCast(value, srcAddr.getElementType(), "icr.writeback-cast"); - + // Perform the writeback. // If we have a "to use" value, it's something we need to emit a use @@ -3146,7 +3186,6 @@ static void emitWritebacks(CodeGenFunction &CGF, static void deactivateArgCleanupsBeforeCall(CodeGenFunction &CGF, const CallArgList &CallArgs) { - assert(CGF.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()); ArrayRef<CallArgList::CallArgCleanup> Cleanups = CallArgs.getCleanupsToDeactivate(); // Iterate in reverse to increase the likelihood of popping the cleanup. @@ -3208,7 +3247,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, // isn't null, so we need to register a dominating point so that the cleanups // system will make valid IR. CodeGenFunction::ConditionalEvaluation condEval(CGF); - + // Zero-initialize it if we're not doing a copy-initialization. bool shouldCopy = CRE->shouldCopy(); if (!shouldCopy) { @@ -3232,7 +3271,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, llvm::Value *isNull = CGF.Builder.CreateIsNull(srcAddr.getPointer(), "icr.isnull"); - finalArgument = CGF.Builder.CreateSelect(isNull, + finalArgument = CGF.Builder.CreateSelect(isNull, llvm::ConstantPointerNull::get(destType), temp.getPointer(), "icr.argument"); @@ -3272,7 +3311,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, valueToUse = src; } } - + // Finish the control flow if we needed it. if (shouldCopy && !provablyNonNull) { llvm::BasicBlock *copyBB = CGF.Builder.GetInsertBlock(); @@ -3323,7 +3362,7 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType, auto PVD = ParmNum < AC.getNumParams() ? AC.getParamDecl(ParmNum) : nullptr; unsigned ArgNo = PVD ? PVD->getFunctionScopeIndex() : ParmNum; - // Prefer the nonnull attribute if it's present. + // Prefer the nonnull attribute if it's present. const NonNullAttr *NNAttr = nullptr; if (SanOpts.has(SanitizerKind::NonnullAttribute)) NNAttr = getNonNullAttr(AC.getDecl(), PVD, ArgType, ArgNo); @@ -3433,13 +3472,17 @@ void CodeGenFunction::EmitCallArgs( assert(InitialArgSize + 1 == Args.size() && "The code below depends on only adding one arg per EmitCallArg"); (void)InitialArgSize; - RValue RVArg = Args.back().RV; - EmitNonNullArgCheck(RVArg, ArgTypes[Idx], (*Arg)->getExprLoc(), AC, - ParamsToSkip + Idx); - // @llvm.objectsize should never have side-effects and shouldn't need - // destruction/cleanups, so we can safely "emit" it after its arg, - // regardless of right-to-leftness - MaybeEmitImplicitObjectSize(Idx, *Arg, RVArg); + // Since pointer argument are never emitted as LValue, it is safe to emit + // non-null argument check for r-value only. + if (!Args.back().hasLValue()) { + RValue RVArg = Args.back().getKnownRValue(); + EmitNonNullArgCheck(RVArg, ArgTypes[Idx], (*Arg)->getExprLoc(), AC, + ParamsToSkip + Idx); + // @llvm.objectsize should never have side-effects and shouldn't need + // destruction/cleanups, so we can safely "emit" it after its arg, + // regardless of right-to-leftness + MaybeEmitImplicitObjectSize(Idx, *Arg, RVArg); + } } if (!LeftToRight) { @@ -3459,10 +3502,15 @@ struct DestroyUnpassedArg final : EHScopeStack::Cleanup { QualType Ty; void Emit(CodeGenFunction &CGF, Flags flags) override { - const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor(); - assert(!Dtor->isTrivial()); - CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*for vbase*/ false, - /*Delegating=*/false, Addr); + QualType::DestructionKind DtorKind = Ty.isDestructedType(); + if (DtorKind == QualType::DK_cxx_destructor) { + const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor(); + assert(!Dtor->isTrivial()); + CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*for vbase*/ false, + /*Delegating=*/false, Addr); + } else { + CGF.callCStructDestructor(CGF.MakeAddrLValue(Addr, Ty)); + } } }; @@ -3481,6 +3529,33 @@ struct DisableDebugLocationUpdates { } // end anonymous namespace +RValue CallArg::getRValue(CodeGenFunction &CGF) const { + if (!HasLV) + return RV; + LValue Copy = CGF.MakeAddrLValue(CGF.CreateMemTemp(Ty), Ty); + CGF.EmitAggregateCopy(Copy, LV, Ty, AggValueSlot::DoesNotOverlap, + LV.isVolatile()); + IsUsed = true; + return RValue::getAggregate(Copy.getAddress()); +} + +void CallArg::copyInto(CodeGenFunction &CGF, Address Addr) const { + LValue Dst = CGF.MakeAddrLValue(Addr, Ty); + if (!HasLV && RV.isScalar()) + CGF.EmitStoreOfScalar(RV.getScalarVal(), Dst, /*init=*/true); + else if (!HasLV && RV.isComplex()) + CGF.EmitStoreOfComplex(RV.getComplexVal(), Dst, /*init=*/true); + else { + auto Addr = HasLV ? LV.getAddress() : RV.getAggregateAddress(); + LValue SrcLV = CGF.MakeAddrLValue(Addr, Ty); + // We assume that call args are never copied into subobjects. + CGF.EmitAggregateCopy(Dst, SrcLV, Ty, AggValueSlot::DoesNotOverlap, + HasLV ? LV.isVolatileQualified() + : RV.isVolatileQualified()); + } + IsUsed = true; +} + void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, QualType type) { DisableDebugLocationUpdates Dis(*this, E); @@ -3504,7 +3579,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, // However, we still have to push an EH-only cleanup in case we unwind before // we make it to the call. if (HasAggregateEvalKind && - CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) { + type->getAs<RecordType>()->getDecl()->isParamDestroyedInCallee()) { // If we're using inalloca, use the argument memory. Otherwise, use a // temporary. AggValueSlot Slot; @@ -3513,10 +3588,12 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, else Slot = CreateAggTemp(type, "agg.tmp"); - const CXXRecordDecl *RD = type->getAsCXXRecordDecl(); - bool DestroyedInCallee = - RD && RD->hasNonTrivialDestructor() && - CGM.getCXXABI().getRecordArgABI(RD) != CGCXXABI::RAA_Default; + bool DestroyedInCallee = true, NeedsEHCleanup = true; + if (const auto *RD = type->getAsCXXRecordDecl()) + DestroyedInCallee = RD->hasNonTrivialDestructor(); + else + NeedsEHCleanup = needsEHCleanup(type.isDestructedType()); + if (DestroyedInCallee) Slot.setExternallyDestructed(); @@ -3524,7 +3601,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, RValue RV = Slot.asRValue(); args.add(RV, type); - if (DestroyedInCallee) { + if (DestroyedInCallee && NeedsEHCleanup) { // Create a no-op GEP between the placeholder and the cleanup so we can // RAUW it successfully. It also serves as a marker of the first // instruction where the cleanup is active. @@ -3541,15 +3618,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue) { LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr()); assert(L.isSimple()); - if (L.getAlignment() >= getContext().getTypeAlignInChars(type)) { - args.add(L.asAggregateRValue(), type, /*NeedsCopy*/true); - } else { - // We can't represent a misaligned lvalue in the CallArgList, so copy - // to an aligned temporary now. - Address tmp = CreateMemTemp(type); - EmitAggregateCopy(tmp, L.getAddress(), type, L.isVolatile()); - args.add(RValue::getAggregate(tmp), type); - } + args.addUncopiedAggregate(L, type); return; } @@ -3611,20 +3680,21 @@ CodeGenFunction::EmitRuntimeCall(llvm::Value *callee, // Calls which may throw must have operand bundles indicating which funclet // they are nested within. -static void -getBundlesForFunclet(llvm::Value *Callee, llvm::Instruction *CurrentFuncletPad, - SmallVectorImpl<llvm::OperandBundleDef> &BundleList) { +SmallVector<llvm::OperandBundleDef, 1> +CodeGenFunction::getBundlesForFunclet(llvm::Value *Callee) { + SmallVector<llvm::OperandBundleDef, 1> BundleList; // There is no need for a funclet operand bundle if we aren't inside a // funclet. if (!CurrentFuncletPad) - return; + return BundleList; // Skip intrinsics which cannot throw. auto *CalleeFn = dyn_cast<llvm::Function>(Callee->stripPointerCasts()); if (CalleeFn && CalleeFn->isIntrinsic() && CalleeFn->doesNotThrow()) - return; + return BundleList; BundleList.emplace_back("funclet", CurrentFuncletPad); + return BundleList; } /// Emits a simple call (never an invoke) to the given runtime function. @@ -3632,10 +3702,8 @@ llvm::CallInst * CodeGenFunction::EmitRuntimeCall(llvm::Value *callee, ArrayRef<llvm::Value*> args, const llvm::Twine &name) { - SmallVector<llvm::OperandBundleDef, 1> BundleList; - getBundlesForFunclet(callee, CurrentFuncletPad, BundleList); - - llvm::CallInst *call = Builder.CreateCall(callee, args, BundleList, name); + llvm::CallInst *call = + Builder.CreateCall(callee, args, getBundlesForFunclet(callee), name); call->setCallingConv(getRuntimeCC()); return call; } @@ -3643,11 +3711,11 @@ CodeGenFunction::EmitRuntimeCall(llvm::Value *callee, /// Emits a call or invoke to the given noreturn runtime function. void CodeGenFunction::EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee, ArrayRef<llvm::Value*> args) { - SmallVector<llvm::OperandBundleDef, 1> BundleList; - getBundlesForFunclet(callee, CurrentFuncletPad, BundleList); + SmallVector<llvm::OperandBundleDef, 1> BundleList = + getBundlesForFunclet(callee); if (getInvokeDest()) { - llvm::InvokeInst *invoke = + llvm::InvokeInst *invoke = Builder.CreateInvoke(callee, getUnreachableBlock(), getInvokeDest(), @@ -3687,8 +3755,8 @@ CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee, ArrayRef<llvm::Value *> Args, const Twine &Name) { llvm::BasicBlock *InvokeDest = getInvokeDest(); - SmallVector<llvm::OperandBundleDef, 1> BundleList; - getBundlesForFunclet(Callee, CurrentFuncletPad, BundleList); + SmallVector<llvm::OperandBundleDef, 1> BundleList = + getBundlesForFunclet(Callee); llvm::Instruction *Inst; if (!InvokeDest) @@ -3708,16 +3776,6 @@ CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee, return llvm::CallSite(Inst); } -/// \brief Store a non-aggregate value to an address to initialize it. For -/// initialization, a non-atomic store will be used. -static void EmitInitStoreOfNonAggregate(CodeGenFunction &CGF, RValue Src, - LValue Dst) { - if (Src.isScalar()) - CGF.EmitStoreOfScalar(Src.getScalarVal(), Dst, /*init=*/true); - else - CGF.EmitStoreOfComplex(Src.getComplexVal(), Dst, /*init=*/true); -} - void CodeGenFunction::deferPlaceholderReplacement(llvm::Instruction *Old, llvm::Value *New) { DeferredReplacements.push_back(std::make_pair(Old, New)); @@ -3731,7 +3789,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, SourceLocation Loc) { // FIXME: We no longer need the types from CallArgs; lift up and simplify. - assert(Callee.isOrdinary()); + assert(Callee.isOrdinary() || Callee.isVirtual()); // Handle struct-return functions by passing a pointer to the // location that we would like to return into. @@ -3778,17 +3836,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // If the call returns a temporary with struct return, create a temporary // alloca to hold the result, unless one is given to us. Address SRetPtr = Address::invalid(); - size_t UnusedReturnSize = 0; + Address SRetAlloca = Address::invalid(); + llvm::Value *UnusedReturnSizePtr = nullptr; if (RetAI.isIndirect() || RetAI.isInAlloca() || RetAI.isCoerceAndExpand()) { if (!ReturnValue.isNull()) { SRetPtr = ReturnValue.getValue(); } else { - SRetPtr = CreateMemTemp(RetTy); + SRetPtr = CreateMemTemp(RetTy, "tmp", &SRetAlloca); if (HaveInsertPoint() && ReturnValue.isUnused()) { uint64_t size = CGM.getDataLayout().getTypeAllocSize(ConvertTypeForMem(RetTy)); - if (EmitLifetimeStart(size, SRetPtr.getPointer())) - UnusedReturnSize = size; + UnusedReturnSizePtr = EmitLifetimeStart(size, SRetAlloca.getPointer()); } } if (IRFunctionArgs.hasSRetArg()) { @@ -3810,7 +3868,6 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, for (CallArgList::const_iterator I = CallArgs.begin(), E = CallArgs.end(); I != E; ++I, ++info_it, ++ArgNo) { const ABIArgInfo &ArgInfo = info_it->info; - RValue RV = I->RV; // Insert a padding argument to ensure proper alignment. if (IRFunctionArgs.hasPaddingArg(ArgNo)) @@ -3824,13 +3881,16 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, case ABIArgInfo::InAlloca: { assert(NumIRArgs == 0); assert(getTarget().getTriple().getArch() == llvm::Triple::x86); - if (RV.isAggregate()) { + if (I->isAggregate()) { // Replace the placeholder with the appropriate argument slot GEP. + Address Addr = I->hasLValue() + ? I->getKnownLValue().getAddress() + : I->getKnownRValue().getAggregateAddress(); llvm::Instruction *Placeholder = - cast<llvm::Instruction>(RV.getAggregatePointer()); + cast<llvm::Instruction>(Addr.getPointer()); CGBuilderTy::InsertPoint IP = Builder.saveIP(); Builder.SetInsertPoint(Placeholder); - Address Addr = createInAllocaStructGEP(ArgInfo.getInAllocaFieldIndex()); + Addr = createInAllocaStructGEP(ArgInfo.getInAllocaFieldIndex()); Builder.restoreIP(IP); deferPlaceholderReplacement(Placeholder, Addr.getPointer()); } else { @@ -3843,22 +3903,20 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // from {}* to (%struct.foo*)*. if (Addr.getType() != MemType) Addr = Builder.CreateBitCast(Addr, MemType); - LValue argLV = MakeAddrLValue(Addr, I->Ty); - EmitInitStoreOfNonAggregate(*this, RV, argLV); + I->copyInto(*this, Addr); } break; } case ABIArgInfo::Indirect: { assert(NumIRArgs == 1); - if (RV.isScalar() || RV.isComplex()) { + if (!I->isAggregate()) { // Make a temporary alloca to pass the argument. - Address Addr = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign(), - "indirect-arg-temp", false); + Address Addr = CreateMemTempWithoutCast( + I->Ty, ArgInfo.getIndirectAlign(), "indirect-arg-temp"); IRCallArgs[FirstIRArg] = Addr.getPointer(); - LValue argLV = MakeAddrLValue(Addr, I->Ty); - EmitInitStoreOfNonAggregate(*this, RV, argLV); + I->copyInto(*this, Addr); } else { // We want to avoid creating an unnecessary temporary+copy here; // however, we need one in three cases: @@ -3866,30 +3924,51 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // source. (This case doesn't occur on any common architecture.) // 2. If the argument is byval, RV is not sufficiently aligned, and // we cannot force it to be sufficiently aligned. - // 3. If the argument is byval, but RV is located in an address space - // different than that of the argument (0). - Address Addr = RV.getAggregateAddress(); + // 3. If the argument is byval, but RV is not located in default + // or alloca address space. + Address Addr = I->hasLValue() + ? I->getKnownLValue().getAddress() + : I->getKnownRValue().getAggregateAddress(); + llvm::Value *V = Addr.getPointer(); CharUnits Align = ArgInfo.getIndirectAlign(); const llvm::DataLayout *TD = &CGM.getDataLayout(); - const unsigned RVAddrSpace = Addr.getType()->getAddressSpace(); - const unsigned ArgAddrSpace = - (FirstIRArg < IRFuncTy->getNumParams() - ? IRFuncTy->getParamType(FirstIRArg)->getPointerAddressSpace() - : 0); - if ((!ArgInfo.getIndirectByVal() && I->NeedsCopy) || - (ArgInfo.getIndirectByVal() && Addr.getAlignment() < Align && - llvm::getOrEnforceKnownAlignment(Addr.getPointer(), - Align.getQuantity(), *TD) - < Align.getQuantity()) || - (ArgInfo.getIndirectByVal() && (RVAddrSpace != ArgAddrSpace))) { + + assert((FirstIRArg >= IRFuncTy->getNumParams() || + IRFuncTy->getParamType(FirstIRArg)->getPointerAddressSpace() == + TD->getAllocaAddrSpace()) && + "indirect argument must be in alloca address space"); + + bool NeedCopy = false; + + if (Addr.getAlignment() < Align && + llvm::getOrEnforceKnownAlignment(V, Align.getQuantity(), *TD) < + Align.getQuantity()) { + NeedCopy = true; + } else if (I->hasLValue()) { + auto LV = I->getKnownLValue(); + auto AS = LV.getAddressSpace(); + if ((!ArgInfo.getIndirectByVal() && + (LV.getAlignment() >= + getContext().getTypeAlignInChars(I->Ty))) || + (ArgInfo.getIndirectByVal() && + ((AS != LangAS::Default && AS != LangAS::opencl_private && + AS != CGM.getASTAllocaAddressSpace())))) { + NeedCopy = true; + } + } + if (NeedCopy) { // Create an aligned temporary, and copy to it. - Address AI = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign(), - "byval-temp", false); + Address AI = CreateMemTempWithoutCast( + I->Ty, ArgInfo.getIndirectAlign(), "byval-temp"); IRCallArgs[FirstIRArg] = AI.getPointer(); - EmitAggregateCopy(AI, Addr, I->Ty, RV.isVolatileQualified()); + I->copyInto(*this, AI); } else { // Skip the extra memcpy call. - IRCallArgs[FirstIRArg] = Addr.getPointer(); + auto *T = V->getType()->getPointerElementType()->getPointerTo( + CGM.getDataLayout().getAllocaAddrSpace()); + IRCallArgs[FirstIRArg] = getTargetHooks().performAddrSpaceCast( + *this, V, LangAS::Default, CGM.getASTAllocaAddressSpace(), T, + true); } } break; @@ -3906,10 +3985,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, ArgInfo.getDirectOffset() == 0) { assert(NumIRArgs == 1); llvm::Value *V; - if (RV.isScalar()) - V = RV.getScalarVal(); + if (!I->isAggregate()) + V = I->getKnownRValue().getScalarVal(); else - V = Builder.CreateLoad(RV.getAggregateAddress()); + V = Builder.CreateLoad( + I->hasLValue() ? I->getKnownLValue().getAddress() + : I->getKnownRValue().getAggregateAddress()); // Implement swifterror by copying into a new swifterror argument. // We'll write back in the normal path out of the call. @@ -3947,12 +4028,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // FIXME: Avoid the conversion through memory if possible. Address Src = Address::invalid(); - if (RV.isScalar() || RV.isComplex()) { + if (!I->isAggregate()) { Src = CreateMemTemp(I->Ty, "coerce"); - LValue SrcLV = MakeAddrLValue(Src, I->Ty); - EmitInitStoreOfNonAggregate(*this, RV, SrcLV); + I->copyInto(*this, Src); } else { - Src = RV.getAggregateAddress(); + Src = I->hasLValue() ? I->getKnownLValue().getAddress() + : I->getKnownRValue().getAggregateAddress(); } // If the value is offset in memory, apply the offset now. @@ -4006,22 +4087,26 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, llvm::Value *tempSize = nullptr; Address addr = Address::invalid(); - if (RV.isAggregate()) { - addr = RV.getAggregateAddress(); + Address AllocaAddr = Address::invalid(); + if (I->isAggregate()) { + addr = I->hasLValue() ? I->getKnownLValue().getAddress() + : I->getKnownRValue().getAggregateAddress(); + } else { + RValue RV = I->getKnownRValue(); assert(RV.isScalar()); // complex should always just be direct llvm::Type *scalarType = RV.getScalarVal()->getType(); auto scalarSize = CGM.getDataLayout().getTypeAllocSize(scalarType); auto scalarAlign = CGM.getDataLayout().getPrefTypeAlignment(scalarType); - tempSize = llvm::ConstantInt::get(CGM.Int64Ty, scalarSize); - // Materialize to a temporary. addr = CreateTempAlloca(RV.getScalarVal()->getType(), - CharUnits::fromQuantity(std::max(layout->getAlignment(), - scalarAlign))); - EmitLifetimeStart(scalarSize, addr.getPointer()); + CharUnits::fromQuantity(std::max( + layout->getAlignment(), scalarAlign)), + "tmp", + /*ArraySize=*/nullptr, &AllocaAddr); + tempSize = EmitLifetimeStart(scalarSize, AllocaAddr.getPointer()); Builder.CreateStore(RV.getScalarVal(), addr); } @@ -4039,7 +4124,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, assert(IRArgPos == FirstIRArg + NumIRArgs); if (tempSize) { - EmitLifetimeEnd(tempSize, addr.getPointer()); + EmitLifetimeEnd(tempSize, AllocaAddr.getPointer()); } break; @@ -4047,13 +4132,14 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, case ABIArgInfo::Expand: unsigned IRArgPos = FirstIRArg; - ExpandTypeToArgs(I->Ty, RV, IRFuncTy, IRCallArgs, IRArgPos); + ExpandTypeToArgs(I->Ty, *I, IRFuncTy, IRCallArgs, IRArgPos); assert(IRArgPos == FirstIRArg + NumIRArgs); break; } } - llvm::Value *CalleePtr = Callee.getFunctionPointer(); + const CGCallee &ConcreteCallee = Callee.prepareConcreteCallee(*this); + llvm::Value *CalleePtr = ConcreteCallee.getFunctionPointer(); // If we're using inalloca, set up that argument. if (ArgMemory.isValid()) { @@ -4194,10 +4280,19 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, CannotThrow = Attrs.hasAttribute(llvm::AttributeList::FunctionIndex, llvm::Attribute::NoUnwind); } + + // If we made a temporary, be sure to clean up after ourselves. Note that we + // can't depend on being inside of an ExprWithCleanups, so we need to manually + // pop this cleanup later on. Being eager about this is OK, since this + // temporary is 'invisible' outside of the callee. + if (UnusedReturnSizePtr) + pushFullExprCleanup<CallLifetimeEnd>(NormalEHLifetimeMarker, SRetAlloca, + UnusedReturnSizePtr); + llvm::BasicBlock *InvokeDest = CannotThrow ? nullptr : getInvokeDest(); - SmallVector<llvm::OperandBundleDef, 1> BundleList; - getBundlesForFunclet(CalleePtr, CurrentFuncletPad, BundleList); + SmallVector<llvm::OperandBundleDef, 1> BundleList = + getBundlesForFunclet(CalleePtr); // Emit the actual call/invoke instruction. llvm::CallSite CS; @@ -4247,9 +4342,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // insertion point; this allows the rest of IRGen to discard // unreachable code. if (CS.doesNotReturn()) { - if (UnusedReturnSize) - EmitLifetimeEnd(llvm::ConstantInt::get(Int64Ty, UnusedReturnSize), - SRetPtr.getPointer()); + if (UnusedReturnSizePtr) + PopCleanupBlock(); // Strip away the noreturn attribute to better diagnose unreachable UB. if (SanOpts.has(SanitizerKind::Unreachable)) { @@ -4318,9 +4412,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, case ABIArgInfo::InAlloca: case ABIArgInfo::Indirect: { RValue ret = convertTempToRValue(SRetPtr, RetTy, SourceLocation()); - if (UnusedReturnSize) - EmitLifetimeEnd(llvm::ConstantInt::get(Int64Ty, UnusedReturnSize), - SRetPtr.getPointer()); + if (UnusedReturnSizePtr) + PopCleanupBlock(); return ret; } @@ -4398,7 +4491,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, OffsetValue); } else if (const auto *AA = TargetDecl->getAttr<AllocAlignAttr>()) { llvm::Value *ParamVal = - CallArgs[AA->getParamIndex() - 1].RV.getScalarVal(); + CallArgs[AA->getParamIndex().getLLVMIndex()].getRValue( + *this).getScalarVal(); EmitAlignmentAssumption(Ret.getScalarVal(), ParamVal); } } @@ -4406,6 +4500,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, return Ret; } +CGCallee CGCallee::prepareConcreteCallee(CodeGenFunction &CGF) const { + if (isVirtual()) { + const CallExpr *CE = getVirtualCallExpr(); + return CGF.CGM.getCXXABI().getVirtualFunctionPointer( + CGF, getVirtualMethodDecl(), getThisAddress(), + getFunctionType(), CE ? CE->getLocStart() : SourceLocation()); + } + + return *this; +} + /* VarArg handling */ Address CodeGenFunction::EmitVAArg(VAArgExpr *VE, Address &VAListAddr) { diff --git a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index 6c3ae24ce1a..b3c5ce1d8cb 100644 --- a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -69,6 +69,9 @@ static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU, std::pair<StringRef, StringRef> Split = Mcpu.split("+"); CPU = Split.first; + if (CPU == "native") + CPU = llvm::sys::getHostCPUName(); + if (CPU == "generic") { Features.push_back("+neon"); } else { @@ -202,6 +205,9 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, if (Args.hasArg(options::OPT_ffixed_x18)) Features.push_back("+reserve-x18"); + if (Args.hasArg(options::OPT_ffixed_x20)) + Features.push_back("+reserve-x20"); + if (Args.hasArg(options::OPT_mno_neg_immediates)) Features.push_back("+no-neg-immediates"); } diff --git a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.cpp index 696cb15ae44..886d947c586 100644 --- a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -391,12 +391,22 @@ void arm::getARMTargetFeatures(const ToolChain &TC, } else if (HDivArg) getARMHWDivFeatures(D, HDivArg, Args, HDivArg->getValue(), Features); - // Setting -msoft-float effectively disables NEON because of the GCC - // implementation, although the same isn't true of VFP or VFP3. + // Setting -msoft-float/-mfloat-abi=soft effectively disables the FPU (GCC + // ignores the -mfpu options in this case). + // Note that the ABI can also be set implicitly by the target selected. if (ABI == arm::FloatABI::Soft) { - Features.push_back("-neon"); - // Also need to explicitly disable features which imply NEON. - Features.push_back("-crypto"); + llvm::ARM::getFPUFeatures(llvm::ARM::FK_NONE, Features); + + // Disable hardware FP features which have been enabled. + // FIXME: Disabling vfp2 and neon should be enough as all the other + // features are dependent on these 2 features in LLVM. However + // there is currently no easy way to test this in clang, so for + // now just be explicit and disable all known dependent features + // as well. + for (std::string Feature : {"vfp2", "vfp3", "vfp4", "fp-armv8", "fullfp16", + "neon", "crypto", "dotprod"}) + if (std::find(std::begin(Features), std::end(Features), "+" + Feature) != std::end(Features)) + Features.push_back(Args.MakeArgString("-" + Feature)); } // En/disable crc code generation. @@ -438,7 +448,7 @@ void arm::getARMTargetFeatures(const ToolChain &TC, if (B->getOption().matches(options::OPT_mlong_calls)) D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args); } - Features.push_back("+execute-only"); + Features.push_back("+execute-only"); } } } diff --git a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp index 5c3953bd478..9c9c1404cba 100644 --- a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp +++ b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp @@ -12,6 +12,7 @@ #include "Arch/ARM.h" #include "Arch/Mips.h" #include "Arch/PPC.h" +#include "Arch/RISCV.h" #include "Arch/Sparc.h" #include "Arch/SystemZ.h" #include "Arch/X86.h" @@ -24,12 +25,12 @@ #include "clang/Basic/LangOptions.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" -#include "clang/Config/config.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "clang/Driver/XRayArgs.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Compression.h" @@ -130,6 +131,10 @@ forAllAssociatedToolChains(Compilation &C, const JobAction &JA, Work(*C.getSingleOffloadToolChain<Action::OFK_Cuda>()); else if (JA.isDeviceOffloading(Action::OFK_Cuda)) Work(*C.getSingleOffloadToolChain<Action::OFK_Host>()); + else if (JA.isHostOffloading(Action::OFK_HIP)) + Work(*C.getSingleOffloadToolChain<Action::OFK_HIP>()); + else if (JA.isDeviceOffloading(Action::OFK_HIP)) + Work(*C.getSingleOffloadToolChain<Action::OFK_Host>()); if (JA.isHostOffloading(Action::OFK_OpenMP)) { auto TCs = C.getOffloadToolChains<Action::OFK_OpenMP>(); @@ -327,6 +332,10 @@ static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, case llvm::Triple::ppc64le: ppc::getPPCTargetFeatures(D, Triple, Args, Features); break; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + riscv::getRISCVTargetFeatures(D, Args, Features); + break; case llvm::Triple::systemz: systemz::getSystemZTargetFeatures(Args, Features); break; @@ -403,7 +412,6 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, const ToolChain &TC, bool KernelOrKext, const ObjCRuntime &objcRuntime, ArgStringList &CmdArgs) { - const Driver &D = TC.getDriver(); const llvm::Triple &Triple = TC.getTriple(); if (KernelOrKext) { @@ -445,21 +453,6 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, ExceptionArg->getOption().matches(options::OPT_fexceptions); if (CXXExceptionsEnabled) { - if (Triple.isPS4CPU()) { - ToolChain::RTTIMode RTTIMode = TC.getRTTIMode(); - assert(ExceptionArg && - "On the PS4 exceptions should only be enabled if passing " - "an argument"); - if (RTTIMode == ToolChain::RM_DisabledExplicitly) { - const Arg *RTTIArg = TC.getRTTIArg(); - assert(RTTIArg && "RTTI disabled explicitly but no RTTIArg!"); - D.Diag(diag::err_drv_argument_not_allowed_with) - << RTTIArg->getAsString(Args) << ExceptionArg->getAsString(Args); - } else if (RTTIMode == ToolChain::RM_EnabledImplicitly) - D.Diag(diag::warn_drv_enabling_rtti_with_exceptions); - } else - assert(TC.getRTTIMode() != ToolChain::RM_DisabledImplicitly); - CmdArgs.push_back("-fcxx-exceptions"); EH = true; @@ -524,10 +517,17 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args, // XCore never wants frame pointers, regardless of OS. // WebAssembly never wants frame pointers. return false; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + return !areOptimizationsEnabled(Args); default: break; } + if (Triple.getOS() == llvm::Triple::NetBSD) { + return !areOptimizationsEnabled(Args); + } + if (Triple.isOSLinux() || Triple.getOS() == llvm::Triple::CloudABI) { switch (Triple.getArch()) { // Don't use a frame pointer on linux if optimizing for certain targets. @@ -604,7 +604,19 @@ static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs) { } } -/// \brief Vectorize at all optimization levels greater than 1 except for -Oz. +/// Add a CC1 and CC1AS option to specify the debug file path prefix map. +static void addDebugPrefixMapArg(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs) { + for (const Arg *A : Args.filtered(options::OPT_fdebug_prefix_map_EQ)) { + StringRef Map = A->getValue(); + if (Map.find('=') == StringRef::npos) + D.Diag(diag::err_drv_invalid_argument_to_fdebug_prefix_map) << Map; + else + CmdArgs.push_back(Args.MakeArgString("-fdebug-prefix-map=" + Map)); + A->claim(); + } +} + +/// Vectorize at all optimization levels greater than 1 except for -Oz. /// For -Oz the loop vectorizer is disable, while the slp vectorizer is enabled. static bool shouldEnableVectorizerAtOLevel(const ArgList &Args, bool isSlpVec) { if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { @@ -826,7 +838,7 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, } } -/// \brief Check whether the given input tree contains any compilation actions. +/// Check whether the given input tree contains any compilation actions. static bool ContainsCompileAction(const Action *A) { if (isa<CompileJobAction>(A) || isa<BackendJobAction>(A)) return true; @@ -838,7 +850,7 @@ static bool ContainsCompileAction(const Action *A) { return false; } -/// \brief Check if -relax-all should be passed to the internal assembler. +/// Check if -relax-all should be passed to the internal assembler. /// This is done by default when compiling non-assembler source with -O0. static bool UseRelaxAll(Compilation &C, const ArgList &Args) { bool RelaxDefault = true; @@ -907,34 +919,46 @@ static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs, } } +static bool checkDebugInfoOption(const Arg *A, const ArgList &Args, + const Driver &D, const ToolChain &TC) { + assert(A && "Expected non-nullptr argument."); + if (TC.supportsDebugInfoOption(A)) + return true; + D.Diag(diag::warn_drv_unsupported_debug_info_opt_for_target) + << A->getAsString(Args) << TC.getTripleString(); + return false; +} + static void RenderDebugInfoCompressionArgs(const ArgList &Args, ArgStringList &CmdArgs, - const Driver &D) { + const Driver &D, + const ToolChain &TC) { const Arg *A = Args.getLastArg(options::OPT_gz, options::OPT_gz_EQ); if (!A) return; + if (checkDebugInfoOption(A, Args, D, TC)) { + if (A->getOption().getID() == options::OPT_gz) { + if (llvm::zlib::isAvailable()) + CmdArgs.push_back("-compress-debug-sections"); + else + D.Diag(diag::warn_debug_compression_unavailable); + return; + } - if (A->getOption().getID() == options::OPT_gz) { - if (llvm::zlib::isAvailable()) - CmdArgs.push_back("-compress-debug-sections"); - else - D.Diag(diag::warn_debug_compression_unavailable); - return; - } - - StringRef Value = A->getValue(); - if (Value == "none") { - CmdArgs.push_back("-compress-debug-sections=none"); - } else if (Value == "zlib" || Value == "zlib-gnu") { - if (llvm::zlib::isAvailable()) { - CmdArgs.push_back( - Args.MakeArgString("-compress-debug-sections=" + Twine(Value))); + StringRef Value = A->getValue(); + if (Value == "none") { + CmdArgs.push_back("-compress-debug-sections=none"); + } else if (Value == "zlib" || Value == "zlib-gnu") { + if (llvm::zlib::isAvailable()) { + CmdArgs.push_back( + Args.MakeArgString("-compress-debug-sections=" + Twine(Value))); + } else { + D.Diag(diag::warn_debug_compression_unavailable); + } } else { - D.Diag(diag::warn_debug_compression_unavailable); + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; } - } else { - D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; } } @@ -1064,73 +1088,28 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, // wonky, but we include looking for .gch so we can support seamless // replacement into a build system already set up to be generating // .gch files. - int YcIndex = -1, YuIndex = -1; - { - int AI = -1; + + if (getToolChain().getDriver().IsCLMode()) { const Arg *YcArg = Args.getLastArg(options::OPT__SLASH_Yc); const Arg *YuArg = Args.getLastArg(options::OPT__SLASH_Yu); - for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) { - // Walk the whole i_Group and skip non "-include" flags so that the index - // here matches the index in the next loop below. - ++AI; - if (!A->getOption().matches(options::OPT_include)) - continue; - if (YcArg && strcmp(A->getValue(), YcArg->getValue()) == 0) - YcIndex = AI; - if (YuArg && strcmp(A->getValue(), YuArg->getValue()) == 0) - YuIndex = AI; + if (YcArg && JA.getKind() >= Action::PrecompileJobClass && + JA.getKind() <= Action::AssembleJobClass) { + CmdArgs.push_back(Args.MakeArgString("-building-pch-with-obj")); + } + if (YcArg || YuArg) { + StringRef ThroughHeader = YcArg ? YcArg->getValue() : YuArg->getValue(); + if (!isa<PrecompileJobAction>(JA)) { + CmdArgs.push_back("-include-pch"); + CmdArgs.push_back(Args.MakeArgString(D.GetClPchPath(C, ThroughHeader))); + } + CmdArgs.push_back( + Args.MakeArgString(Twine("-pch-through-header=") + ThroughHeader)); } - } - if (isa<PrecompileJobAction>(JA) && YcIndex != -1) { - Driver::InputList Inputs; - D.BuildInputs(getToolChain(), C.getArgs(), Inputs); - assert(Inputs.size() == 1 && "Need one input when building pch"); - CmdArgs.push_back(Args.MakeArgString(Twine("-find-pch-source=") + - Inputs[0].second->getValue())); } bool RenderedImplicitInclude = false; - int AI = -1; for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) { - ++AI; - - if (getToolChain().getDriver().IsCLMode() && - A->getOption().matches(options::OPT_include)) { - // In clang-cl mode, /Ycfoo.h means that all code up to a foo.h - // include is compiled into foo.h, and everything after goes into - // the .obj file. /Yufoo.h means that all includes prior to and including - // foo.h are completely skipped and replaced with a use of the pch file - // for foo.h. (Each flag can have at most one value, multiple /Yc flags - // just mean that the last one wins.) If /Yc and /Yu are both present - // and refer to the same file, /Yc wins. - // Note that OPT__SLASH_FI gets mapped to OPT_include. - // FIXME: The code here assumes that /Yc and /Yu refer to the same file. - // cl.exe seems to support both flags with different values, but that - // seems strange (which flag does /Fp now refer to?), so don't implement - // that until someone needs it. - int PchIndex = YcIndex != -1 ? YcIndex : YuIndex; - if (PchIndex != -1) { - if (isa<PrecompileJobAction>(JA)) { - // When building the pch, skip all includes after the pch. - assert(YcIndex != -1 && PchIndex == YcIndex); - if (AI >= YcIndex) - continue; - } else { - // When using the pch, skip all includes prior to the pch. - if (AI < PchIndex) { - A->claim(); - continue; - } - if (AI == PchIndex) { - A->claim(); - CmdArgs.push_back("-include-pch"); - CmdArgs.push_back( - Args.MakeArgString(D.GetClPchPath(C, A->getValue()))); - continue; - } - } - } - } else if (A->getOption().matches(options::OPT_include)) { + if (A->getOption().matches(options::OPT_include)) { // Handling of gcc-style gch precompiled headers. bool IsFirstImplicitInclude = !RenderedImplicitInclude; RenderedImplicitInclude = true; @@ -1282,6 +1261,8 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) { case llvm::Triple::hexagon: case llvm::Triple::ppc64le: + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: case llvm::Triple::systemz: case llvm::Triple::xcore: return false; @@ -1291,6 +1272,8 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) { static bool isNoCommonDefault(const llvm::Triple &Triple) { switch (Triple.getArch()) { default: + if (Triple.isOSFuchsia()) + return true; return false; case llvm::Triple::xcore: @@ -1338,7 +1321,7 @@ void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, // Forward the -mglobal-merge option for explicit control over the pass. if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge, options::OPT_mno_global_merge)) { - CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-mllvm"); if (A->getOption().matches(options::OPT_mno_global_merge)) CmdArgs.push_back("-arm-global-merge=false"); else @@ -1391,6 +1374,11 @@ void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, AddPPCTargetArgs(Args, CmdArgs); break; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + AddRISCVTargetArgs(Args, CmdArgs); + break; + case llvm::Triple::sparc: case llvm::Triple::sparcel: case llvm::Triple::sparcv9: @@ -1447,21 +1435,21 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a53_835769, options::OPT_mno_fix_cortex_a53_835769)) { - CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-mllvm"); if (A->getOption().matches(options::OPT_mfix_cortex_a53_835769)) CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1"); else CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=0"); } else if (Triple.isAndroid()) { // Enabled A53 errata (835769) workaround by default on android - CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1"); } // Forward the -mglobal-merge option for explicit control over the pass. if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge, options::OPT_mno_global_merge)) { - CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-mllvm"); if (A->getOption().matches(options::OPT_mno_global_merge)) CmdArgs.push_back("-aarch64-enable-global-merge=false"); else @@ -1668,6 +1656,25 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, } } +void Clang::AddRISCVTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // FIXME: currently defaults to the soft-float ABIs. Will need to be + // expanded to select ilp32f, ilp32d, lp64f, lp64d when appropriate. + const char *ABIName = nullptr; + const llvm::Triple &Triple = getToolChain().getTriple(); + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) + ABIName = A->getValue(); + else if (Triple.getArch() == llvm::Triple::riscv32) + ABIName = "ilp32"; + else if (Triple.getArch() == llvm::Triple::riscv64) + ABIName = "lp64"; + else + llvm_unreachable("Unexpected triple!"); + + CmdArgs.push_back("-target-abi"); + CmdArgs.push_back(ABIName); +} + void Clang::AddSparcTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { sparc::FloatABI FloatABI = @@ -1722,6 +1729,9 @@ void Clang::AddX86TargetArgs(const ArgList &Args, getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; } + } else if (getToolChain().getDriver().IsCLMode()) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-x86-asm-syntax=intel"); } // Set flags to support MCU ABI. @@ -2043,7 +2053,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, // Handle various floating point optimization flags, mapping them to the // appropriate LLVM code generation flags. This is complicated by several // "umbrella" flags, so we do this by stepping through the flags incrementally - // adjusting what we think is enabled/disabled, then at the end settting the + // adjusting what we think is enabled/disabled, then at the end setting the // LLVM flags based on the final state. bool HonorINFs = true; bool HonorNaNs = true; @@ -2202,6 +2212,11 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, CmdArgs.push_back("-mfpmath"); CmdArgs.push_back(A->getValue()); } + + // Disable a codegen optimization for floating-point casts. + if (Args.hasFlag(options::OPT_fno_strict_float_cast_overflow, + options::OPT_fstrict_float_cast_overflow, false)) + CmdArgs.push_back("-fno-strict-float-cast-overflow"); } static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs, @@ -2337,6 +2352,7 @@ static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs) { options::OPT_cl_no_signed_zeros, options::OPT_cl_denorms_are_zero, options::OPT_cl_fp32_correctly_rounded_divide_sqrt, + options::OPT_cl_uniform_work_group_size }; if (Arg *A = Args.getLastArg(options::OPT_cl_std_EQ)) { @@ -2458,6 +2474,13 @@ static void RenderBuiltinOptions(const ToolChain &TC, const llvm::Triple &T, CmdArgs.push_back("-fno-math-builtin"); } +void Driver::getDefaultModuleCachePath(SmallVectorImpl<char> &Result) { + llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, Result); + llvm::sys::path::append(Result, "org.llvm.clang."); + appendUserToPath(Result); + llvm::sys::path::append(Result, "ModuleCache"); +} + static void RenderModulesOptions(Compilation &C, const Driver &D, const ArgList &Args, const InputInfo &Input, const InputInfo &Output, @@ -2499,11 +2522,13 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, CmdArgs.push_back("-fmodules-strict-decluse"); // -fno-implicit-modules turns off implicitly compiling modules on demand. + bool ImplicitModules = false; if (!Args.hasFlag(options::OPT_fimplicit_modules, options::OPT_fno_implicit_modules, HaveClangModules)) { if (HaveModules) CmdArgs.push_back("-fno-implicit-modules"); } else if (HaveModules) { + ImplicitModules = true; // -fmodule-cache-path specifies where our implicitly-built module files // should be written. SmallString<128> Path; @@ -2518,10 +2543,7 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, llvm::sys::path::append(Path, "modules"); } else if (Path.empty()) { // No module path was provided: use the default. - llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, Path); - llvm::sys::path::append(Path, "org.llvm.clang."); - appendUserToPath(Path); - llvm::sys::path::append(Path, "ModuleCache"); + Driver::getDefaultModuleCachePath(Path); } const char Arg[] = "-fmodules-cache-path="; @@ -2613,7 +2635,11 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, options::OPT_fmodules_validate_once_per_build_session); } - Args.AddLastArg(CmdArgs, options::OPT_fmodules_validate_system_headers); + if (Args.hasFlag(options::OPT_fmodules_validate_system_headers, + options::OPT_fno_modules_validate_system_headers, + ImplicitModules)) + CmdArgs.push_back("-fmodules-validate-system-headers"); + Args.AddLastArg(CmdArgs, options::OPT_fmodules_disable_diagnostic_validation); } @@ -2632,6 +2658,9 @@ static void RenderCharacterOptions(const ArgList &Args, const llvm::Triple &T, CmdArgs.push_back("-fno-signed-char"); } + if (Args.hasFlag(options::OPT_fchar8__t, options::OPT_fno_char8__t, false)) + CmdArgs.push_back("-fchar8_t"); + if (const Arg *A = Args.getLastArg(options::OPT_fshort_wchar, options::OPT_fno_short_wchar)) { if (A->getOption().matches(options::OPT_fshort_wchar)) { @@ -2850,7 +2879,9 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, codegenoptions::DebugInfoKind &DebugInfoKind, const Arg *&SplitDWARFArg) { if (Args.hasFlag(options::OPT_fdebug_info_for_profiling, - options::OPT_fno_debug_info_for_profiling, false)) + options::OPT_fno_debug_info_for_profiling, false) && + checkDebugInfoOption( + Args.getLastArg(options::OPT_fdebug_info_for_profiling), Args, D, TC)) CmdArgs.push_back("-fdebug-info-for-profiling"); // The 'g' groups options involve a somewhat intricate sequence of decisions @@ -2873,29 +2904,38 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, SplitDWARFArg = Args.getLastArg(options::OPT_gsplit_dwarf); + if (SplitDWARFArg && !checkDebugInfoOption(SplitDWARFArg, Args, D, TC)) { + SplitDWARFArg = nullptr; + SplitDWARFInlining = false; + } + if (const Arg *A = Args.getLastArg(options::OPT_g_Group)) { - // If the last option explicitly specified a debug-info level, use it. - if (A->getOption().matches(options::OPT_gN_Group)) { - DebugInfoKind = DebugLevelToInfoKind(*A); - // If you say "-gsplit-dwarf -gline-tables-only", -gsplit-dwarf loses. - // But -gsplit-dwarf is not a g_group option, hence we have to check the - // order explicitly. If -gsplit-dwarf wins, we fix DebugInfoKind later. - // This gets a bit more complicated if you've disabled inline info in the - // skeleton CUs (SplitDWARFInlining) - then there's value in composing - // split-dwarf and line-tables-only, so let those compose naturally in - // that case. - // And if you just turned off debug info, (-gsplit-dwarf -g0) - do that. - if (SplitDWARFArg) { - if (A->getIndex() > SplitDWARFArg->getIndex()) { - if (DebugInfoKind == codegenoptions::NoDebugInfo || - (DebugInfoKind == codegenoptions::DebugLineTablesOnly && - SplitDWARFInlining)) - SplitDWARFArg = nullptr; - } else if (SplitDWARFInlining) - DebugInfoKind = codegenoptions::NoDebugInfo; + if (checkDebugInfoOption(A, Args, D, TC)) { + // If the last option explicitly specified a debug-info level, use it. + if (A->getOption().matches(options::OPT_gN_Group)) { + DebugInfoKind = DebugLevelToInfoKind(*A); + // If you say "-gsplit-dwarf -gline-tables-only", -gsplit-dwarf loses. + // But -gsplit-dwarf is not a g_group option, hence we have to check the + // order explicitly. If -gsplit-dwarf wins, we fix DebugInfoKind later. + // This gets a bit more complicated if you've disabled inline info in + // the skeleton CUs (SplitDWARFInlining) - then there's value in + // composing split-dwarf and line-tables-only, so let those compose + // naturally in that case. And if you just turned off debug info, + // (-gsplit-dwarf -g0) - do that. + if (SplitDWARFArg) { + if (A->getIndex() > SplitDWARFArg->getIndex()) { + if (DebugInfoKind == codegenoptions::NoDebugInfo || + (DebugInfoKind == codegenoptions::DebugLineTablesOnly && + SplitDWARFInlining)) + SplitDWARFArg = nullptr; + } else if (SplitDWARFInlining) + DebugInfoKind = codegenoptions::NoDebugInfo; + } + } else { + // For any other 'g' option, use Limited. + DebugInfoKind = codegenoptions::LimitedDebugInfo; } } else { - // For any other 'g' option, use Limited. DebugInfoKind = codegenoptions::LimitedDebugInfo; } } @@ -2903,52 +2943,65 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, // If a debugger tuning argument appeared, remember it. if (const Arg *A = Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) { - if (A->getOption().matches(options::OPT_glldb)) - DebuggerTuning = llvm::DebuggerKind::LLDB; - else if (A->getOption().matches(options::OPT_gsce)) - DebuggerTuning = llvm::DebuggerKind::SCE; - else - DebuggerTuning = llvm::DebuggerKind::GDB; + if (checkDebugInfoOption(A, Args, D, TC)) { + if (A->getOption().matches(options::OPT_glldb)) + DebuggerTuning = llvm::DebuggerKind::LLDB; + else if (A->getOption().matches(options::OPT_gsce)) + DebuggerTuning = llvm::DebuggerKind::SCE; + else + DebuggerTuning = llvm::DebuggerKind::GDB; + } } // If a -gdwarf argument appeared, remember it. if (const Arg *A = Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3, options::OPT_gdwarf_4, options::OPT_gdwarf_5)) - DWARFVersion = DwarfVersionNum(A->getSpelling()); + if (checkDebugInfoOption(A, Args, D, TC)) + DWARFVersion = DwarfVersionNum(A->getSpelling()); // Forward -gcodeview. EmitCodeView might have been set by CL-compatibility // argument parsing. - if (Args.hasArg(options::OPT_gcodeview) || EmitCodeView) { - // DWARFVersion remains at 0 if no explicit choice was made. - CmdArgs.push_back("-gcodeview"); - } else if (DWARFVersion == 0 && - DebugInfoKind != codegenoptions::NoDebugInfo) { - DWARFVersion = TC.GetDefaultDwarfVersion(); + if (EmitCodeView) { + if (const Arg *A = Args.getLastArg(options::OPT_gcodeview)) { + EmitCodeView = checkDebugInfoOption(A, Args, D, TC); + if (EmitCodeView) { + // DWARFVersion remains at 0 if no explicit choice was made. + CmdArgs.push_back("-gcodeview"); + } + } } + if (!EmitCodeView && DWARFVersion == 0 && + DebugInfoKind != codegenoptions::NoDebugInfo) + DWARFVersion = TC.GetDefaultDwarfVersion(); + // We ignore flag -gstrict-dwarf for now. // And we handle flag -grecord-gcc-switches later with DWARFDebugFlags. Args.ClaimAllArgs(options::OPT_g_flags_Group); - // Column info is included by default for everything except SCE and CodeView. - // Clang doesn't track end columns, just starting columns, which, in theory, - // is fine for CodeView (and PDB). In practice, however, the Microsoft - // debuggers don't handle missing end columns well, so it's better not to - // include any column info. + // Column info is included by default for everything except SCE and + // CodeView. Clang doesn't track end columns, just starting columns, which, + // in theory, is fine for CodeView (and PDB). In practice, however, the + // Microsoft debuggers don't handle missing end columns well, so it's better + // not to include any column info. + if (const Arg *A = Args.getLastArg(options::OPT_gcolumn_info)) + (void)checkDebugInfoOption(A, Args, D, TC); if (Args.hasFlag(options::OPT_gcolumn_info, options::OPT_gno_column_info, - /*Default=*/!(IsWindowsMSVC && EmitCodeView) && + /*Default=*/!EmitCodeView && DebuggerTuning != llvm::DebuggerKind::SCE)) CmdArgs.push_back("-dwarf-column-info"); // FIXME: Move backend command line options to the module. // If -gline-tables-only is the last option it wins. - if (DebugInfoKind != codegenoptions::DebugLineTablesOnly && - Args.hasArg(options::OPT_gmodules)) { - DebugInfoKind = codegenoptions::LimitedDebugInfo; - CmdArgs.push_back("-dwarf-ext-refs"); - CmdArgs.push_back("-fmodule-format=obj"); - } + if (const Arg *A = Args.getLastArg(options::OPT_gmodules)) + if (checkDebugInfoOption(A, Args, D, TC)) { + if (DebugInfoKind != codegenoptions::DebugLineTablesOnly) { + DebugInfoKind = codegenoptions::LimitedDebugInfo; + CmdArgs.push_back("-dwarf-ext-refs"); + CmdArgs.push_back("-fmodule-format=obj"); + } + } // -gsplit-dwarf should turn on -g and enable the backend dwarf // splitting and extraction. @@ -2972,34 +3025,66 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, bool NeedFullDebug = Args.hasFlag(options::OPT_fstandalone_debug, options::OPT_fno_standalone_debug, TC.GetDefaultStandaloneDebug()); + if (const Arg *A = Args.getLastArg(options::OPT_fstandalone_debug)) + (void)checkDebugInfoOption(A, Args, D, TC); if (DebugInfoKind == codegenoptions::LimitedDebugInfo && NeedFullDebug) DebugInfoKind = codegenoptions::FullDebugInfo; + if (Args.hasFlag(options::OPT_gembed_source, options::OPT_gno_embed_source, + false)) { + // Source embedding is a vendor extension to DWARF v5. By now we have + // checked if a DWARF version was stated explicitly, and have otherwise + // fallen back to the target default, so if this is still not at least 5 + // we emit an error. + const Arg *A = Args.getLastArg(options::OPT_gembed_source); + if (DWARFVersion < 5) + D.Diag(diag::err_drv_argument_only_allowed_with) + << A->getAsString(Args) << "-gdwarf-5"; + else if (checkDebugInfoOption(A, Args, D, TC)) + CmdArgs.push_back("-gembed-source"); + } + RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DWARFVersion, DebuggerTuning); // -fdebug-macro turns on macro debug info generation. if (Args.hasFlag(options::OPT_fdebug_macro, options::OPT_fno_debug_macro, false)) - CmdArgs.push_back("-debug-info-macro"); + if (checkDebugInfoOption(Args.getLastArg(options::OPT_fdebug_macro), Args, + D, TC)) + CmdArgs.push_back("-debug-info-macro"); // -ggnu-pubnames turns on gnu style pubnames in the backend. - if (Args.hasArg(options::OPT_ggnu_pubnames)) - CmdArgs.push_back("-ggnu-pubnames"); + if (Args.hasFlag(options::OPT_ggnu_pubnames, options::OPT_gno_gnu_pubnames, + false)) + if (checkDebugInfoOption(Args.getLastArg(options::OPT_ggnu_pubnames), Args, + D, TC)) + CmdArgs.push_back("-ggnu-pubnames"); // -gdwarf-aranges turns on the emission of the aranges section in the // backend. // Always enabled for SCE tuning. - if (Args.hasArg(options::OPT_gdwarf_aranges) || - DebuggerTuning == llvm::DebuggerKind::SCE) { - CmdArgs.push_back("-backend-option"); + bool NeedAranges = DebuggerTuning == llvm::DebuggerKind::SCE; + if (const Arg *A = Args.getLastArg(options::OPT_gdwarf_aranges)) + NeedAranges = checkDebugInfoOption(A, Args, D, TC) || NeedAranges; + if (NeedAranges) { + CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-generate-arange-section"); } if (Args.hasFlag(options::OPT_fdebug_types_section, options::OPT_fno_debug_types_section, false)) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-generate-type-units"); + if (!T.isOSBinFormatELF()) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Args.getLastArg(options::OPT_fdebug_types_section) + ->getAsString(Args) + << T.getTriple(); + } else if (checkDebugInfoOption( + Args.getLastArg(options::OPT_fdebug_types_section), Args, D, + TC)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-generate-type-units"); + } } // Decide how to render forward declarations of template instantiations. @@ -3007,11 +3092,12 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, if (DebuggerTuning == llvm::DebuggerKind::SCE) CmdArgs.push_back("-debug-forward-template-params"); - // Do we need to explicitly import anonymous namespaces into the parent scope? + // Do we need to explicitly import anonymous namespaces into the parent + // scope? if (DebuggerTuning == llvm::DebuggerKind::SCE) CmdArgs.push_back("-dwarf-explicit-import"); - RenderDebugInfoCompressionArgs(Args, CmdArgs, D); + RenderDebugInfoCompressionArgs(Args, CmdArgs, D, TC); } void Clang::ConstructJob(Compilation &C, const JobAction &JA, @@ -3029,13 +3115,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Check number of inputs for sanity. We need at least one input. assert(Inputs.size() >= 1 && "Must have at least one input."); const InputInfo &Input = Inputs[0]; - // CUDA compilation may have multiple inputs (source file + results of + // CUDA/HIP compilation may have multiple inputs (source file + results of // device-side compilations). OpenMP device jobs also take the host IR as a // second input. All other jobs are expected to have exactly one // input. bool IsCuda = JA.isOffloading(Action::OFK_Cuda); + bool IsHIP = JA.isOffloading(Action::OFK_HIP); bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP); - assert((IsCuda || (IsOpenMPDevice && Inputs.size() == 2) || + assert((IsCuda || IsHIP || (IsOpenMPDevice && Inputs.size() == 2) || Inputs.size() == 1) && "Unable to handle multiple inputs."); @@ -3047,10 +3134,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, bool IsWindowsMSVC = RawTriple.isWindowsMSVCEnvironment(); bool IsIAMCU = RawTriple.isOSIAMCU(); - // Adjust IsWindowsXYZ for CUDA compilations. Even when compiling in device - // mode (i.e., getToolchain().getTriple() is NVPTX, not Windows), we need to - // pass Windows-specific flags to cc1. - if (IsCuda) { + // Adjust IsWindowsXYZ for CUDA/HIP compilations. Even when compiling in + // device mode (i.e., getToolchain().getTriple() is NVPTX/AMDGCN, not + // Windows), we need to pass Windows-specific flags to cc1. + if (IsCuda || IsHIP) { IsWindowsMSVC |= AuxTriple && AuxTriple->isWindowsMSVCEnvironment(); IsWindowsGNU |= AuxTriple && AuxTriple->isWindowsGNUEnvironment(); IsWindowsCygnus |= AuxTriple && AuxTriple->isWindowsCygwinEnvironment(); @@ -3074,18 +3161,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.ClaimAllArgs(options::OPT_MJ); } - if (IsCuda) { - // We have to pass the triple of the host if compiling for a CUDA device and - // vice-versa. + if (IsCuda || IsHIP) { + // We have to pass the triple of the host if compiling for a CUDA/HIP device + // and vice-versa. std::string NormalizedTriple; - if (JA.isDeviceOffloading(Action::OFK_Cuda)) + if (JA.isDeviceOffloading(Action::OFK_Cuda) || + JA.isDeviceOffloading(Action::OFK_HIP)) NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Host>() ->getTriple() .normalize(); else - NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Cuda>() - ->getTriple() - .normalize(); + NormalizedTriple = + (IsCuda ? C.getSingleOffloadToolChain<Action::OFK_Cuda>() + : C.getSingleOffloadToolChain<Action::OFK_HIP>()) + ->getTriple() + .normalize(); CmdArgs.push_back("-aux-triple"); CmdArgs.push_back(Args.MakeArgString(NormalizedTriple)); @@ -3188,7 +3278,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (JA.getType() == types::TY_LLVM_BC) CmdArgs.push_back("-emit-llvm-uselists"); - if (D.isUsingLTO()) { + // Device-side jobs do not support LTO. + bool isDeviceOffloadAction = !(JA.isDeviceOffloading(Action::OFK_None) || + JA.isDeviceOffloading(Action::OFK_Host)); + + if (D.isUsingLTO() && !isDeviceOffloadAction) { Args.AddLastArg(CmdArgs, options::OPT_flto, options::OPT_flto_EQ); // The Darwin and PS4 linkers currently use the legacy LTO API, which @@ -3207,6 +3301,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ); } + if (Args.getLastArg(options::OPT_save_temps_EQ)) + Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ); + // Embed-bitcode option. if (C.getDriver().embedBitcodeInObject() && !C.getDriver().isUsingLTO() && (isa<BackendJobAction>(JA) || isa<AssembleJobAction>(JA))) { @@ -3224,13 +3321,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!C.isForDiagnostics()) CmdArgs.push_back("-disable-free"); -// Disable the verification pass in -asserts builds. #ifdef NDEBUG - CmdArgs.push_back("-disable-llvm-verifier"); - // Discard LLVM value names in -asserts builds. - CmdArgs.push_back("-discard-value-names"); + const bool IsAssertBuild = false; +#else + const bool IsAssertBuild = true; #endif + // Disable the verification pass in -asserts builds. + if (!IsAssertBuild) + CmdArgs.push_back("-disable-llvm-verifier"); + + // Discard value names in assert builds unless otherwise specified. + if (Args.hasFlag(options::OPT_fdiscard_value_names, + options::OPT_fno_discard_value_names, !IsAssertBuild)) + CmdArgs.push_back("-discard-value-names"); + // Set the main file name, so that debug info works even with // -save-temps. CmdArgs.push_back("-main-file-name"); @@ -3246,6 +3351,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CheckCodeGenerationOptions(D, Args); + unsigned FunctionAlignment = ParseFunctionAlignment(getToolChain(), Args); + assert(FunctionAlignment <= 31 && "function alignment will be truncated!"); + if (FunctionAlignment) { + CmdArgs.push_back("-function-alignment"); + CmdArgs.push_back(Args.MakeArgString(std::to_string(FunctionAlignment))); + } + llvm::Reloc::Model RelocationModel; unsigned PICLevel; bool IsPIE; @@ -3288,9 +3400,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fveclib); - if (!Args.hasFlag(options::OPT_fmerge_all_constants, - options::OPT_fno_merge_all_constants)) - CmdArgs.push_back("-fno-merge-all-constants"); + if (Args.hasFlag(options::OPT_fmerge_all_constants, + options::OPT_fno_merge_all_constants, false)) + CmdArgs.push_back("-fmerge-all-constants"); + + if (Args.hasFlag(options::OPT_fno_delete_null_pointer_checks, + options::OPT_fdelete_null_pointer_checks, false)) + CmdArgs.push_back("-fno-delete-null-pointer-checks"); // LLVM Code Generator Options. @@ -3385,9 +3501,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_strict_vtable_pointers, false)) CmdArgs.push_back("-fstrict-vtable-pointers"); + if (Args.hasFlag(options::OPT_fforce_emit_vtables, + options::OPT_fno_force_emit_vtables, + false)) + CmdArgs.push_back("-fforce-emit-vtables"); if (!Args.hasFlag(options::OPT_foptimize_sibling_calls, options::OPT_fno_optimize_sibling_calls)) CmdArgs.push_back("-mdisable-tail-calls"); + if (Args.hasFlag(options::OPT_fno_escaping_block_tail_calls, + options::OPT_fescaping_block_tail_calls, false)) + CmdArgs.push_back("-fno-escaping-block-tail-calls"); Args.AddLastArg(CmdArgs, options::OPT_ffine_grained_bitfield_accesses, options::OPT_fno_fine_grained_bitfield_accesses); @@ -3407,8 +3530,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.hasArg(options::OPT_dA)) CmdArgs.push_back("-masm-verbose"); - if (!Args.hasFlag(options::OPT_fintegrated_as, options::OPT_fno_integrated_as, - IsIntegratedAssemblerDefault)) + if (!getToolChain().useIntegratedAs()) CmdArgs.push_back("-no-integrated-as"); if (Args.hasArg(options::OPT_fdebug_pass_structure)) { @@ -3501,6 +3623,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, types::ID InputType = Input.getType(); if (D.IsCLMode()) AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView); + else + EmitCodeView = Args.hasArg(options::OPT_gcodeview); const Arg *SplitDWARFArg = nullptr; RenderDebugOptions(getToolChain(), D, RawTriple, Args, EmitCodeView, @@ -3586,14 +3710,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_finstrument_function_entry_bare)) A->render(Args, CmdArgs); - addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs); + // NVPTX doesn't support PGO or coverage. There's no runtime support for + // sampling, overhead of call arc collection is way too high and there's no + // way to collect the output. + if (!Triple.isNVPTX()) + addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs); if (auto *ABICompatArg = Args.getLastArg(options::OPT_fclang_abi_compat_EQ)) ABICompatArg->render(Args, CmdArgs); - // Add runtime flag for PS4 when PGO or Coverage are enabled. - if (RawTriple.isPS4CPU()) + // Add runtime flag for PS4 when PGO, coverage, or sanitizers are enabled. + if (RawTriple.isPS4CPU()) { PS4cpu::addProfileRTArgs(getToolChain(), Args, CmdArgs); + PS4cpu::addSanitizerArgs(getToolChain(), CmdArgs); + } // Pass options for controlling the default header search paths. if (Args.hasArg(options::OPT_nostdinc)) { @@ -3660,6 +3790,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors); Args.AddLastArg(CmdArgs, options::OPT_w); + // Fixed point flags + if (Args.hasFlag(options::OPT_ffixed_point, options::OPT_fno_fixed_point, + /*Default=*/false)) + Args.AddLastArg(CmdArgs, options::OPT_ffixed_point); + // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi} // (-ansi is equivalent to -std=c89 or -std=c++98). // @@ -3744,14 +3879,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Add in -fdebug-compilation-dir if necessary. addDebugCompDirArg(Args, CmdArgs); - for (const Arg *A : Args.filtered(options::OPT_fdebug_prefix_map_EQ)) { - StringRef Map = A->getValue(); - if (Map.find('=') == StringRef::npos) - D.Diag(diag::err_drv_invalid_argument_to_fdebug_prefix_map) << Map; - else - CmdArgs.push_back(Args.MakeArgString("-fdebug-prefix-map=" + Map)); - A->claim(); - } + addDebugPrefixMapArg(D, Args, CmdArgs); if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_, options::OPT_ftemplate_depth_EQ)) { @@ -3801,6 +3929,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } + if (Args.hasFlag(options::OPT_fstack_size_section, + options::OPT_fno_stack_size_section, RawTriple.isPS4())) + CmdArgs.push_back("-fstack-size-section"); + CmdArgs.push_back("-ferror-limit"); if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ)) CmdArgs.push_back(A->getValue()); @@ -3860,14 +3992,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Forward -f (flag) options which we can pass directly. Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); + Args.AddLastArg(CmdArgs, options::OPT_fdigraphs, options::OPT_fno_digraphs); Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names); - // Emulated TLS is enabled by default on Android and OpenBSD, and can be enabled - // manually with -femulated-tls. - bool EmulatedTLSDefault = Triple.isAndroid() || Triple.isOSOpenBSD() || - Triple.isWindowsCygwinEnvironment(); - if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls, - EmulatedTLSDefault)) - CmdArgs.push_back("-femulated-tls"); + Args.AddLastArg(CmdArgs, options::OPT_femulated_tls, + options::OPT_fno_emulated_tls); + // AltiVec-like language extensions aren't relevant for assembling. if (!isa<PreprocessJobAction>(JA) || Output.getType() != types::TY_PP_Asm) Args.AddLastArg(CmdArgs, options::OPT_fzvector); @@ -3893,7 +4022,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasFlag(options::OPT_fopenmp_use_tls, options::OPT_fnoopenmp_use_tls, /*Default=*/true)) CmdArgs.push_back("-fnoopenmp-use-tls"); + Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd, + options::OPT_fno_openmp_simd); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ); + + // When in OpenMP offloading mode with NVPTX target, forward + // cuda-mode flag + Args.AddLastArg(CmdArgs, options::OPT_fopenmp_cuda_mode, + options::OPT_fno_openmp_cuda_mode); break; default: // By default, if Clang doesn't know how to generate useful OpenMP code @@ -4006,26 +4142,35 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mstack-probe-size=0"); } + if (!Args.hasFlag(options::OPT_mstack_arg_probe, + options::OPT_mno_stack_arg_probe, true)) + CmdArgs.push_back(Args.MakeArgString("-mno-stack-arg-probe")); + if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it, options::OPT_mno_restrict_it)) { if (A->getOption().matches(options::OPT_mrestrict_it)) { - CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-arm-restrict-it"); } else { - CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-arm-no-restrict-it"); } } else if (Triple.isOSWindows() && (Triple.getArch() == llvm::Triple::arm || Triple.getArch() == llvm::Triple::thumb)) { // Windows on ARM expects restricted IT blocks - CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-arm-restrict-it"); } // Forward -cl options to -cc1 RenderOpenCLOptions(Args, CmdArgs); + if (Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) { + CmdArgs.push_back( + Args.MakeArgString(Twine("-fcf-protection=") + A->getValue())); + } + // Forward -f options with positive and negative forms; we translate // these by hand. if (Arg *A = getLastProfileSampleUseArg(Args)) { @@ -4084,8 +4229,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, ToolChain::RTTIMode RTTIMode = getToolChain().getRTTIMode(); if (KernelOrKext || (types::isCXX(InputType) && - (RTTIMode == ToolChain::RM_DisabledExplicitly || - RTTIMode == ToolChain::RM_DisabledImplicitly))) + (RTTIMode == ToolChain::RM_Disabled))) CmdArgs.push_back("-fno-rtti"); // -fshort-enums=0 is default for all architectures except Hexagon. @@ -4107,6 +4251,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, KernelOrKext) CmdArgs.push_back("-fno-use-cxa-atexit"); + if (Args.hasFlag(options::OPT_fregister_global_dtors_with_atexit, + options::OPT_fno_register_global_dtors_with_atexit, + RawTriple.isOSDarwin() && !KernelOrKext)) + CmdArgs.push_back("-fregister-global-dtors-with-atexit"); + // -fms-extensions=0 is default. if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, IsWindowsMSVC)) @@ -4173,7 +4322,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, !IsWindowsMSVC || IsMSVC2015Compatible)) CmdArgs.push_back("-fno-threadsafe-statics"); - // -fno-delayed-template-parsing is default, except when targetting MSVC. + // -fno-delayed-template-parsing is default, except when targeting MSVC. // Many old Windows SDK versions require this to parse. // FIXME: MSVC introduced /Zc:twoPhase- to disable this behavior in their // compiler. We should be able to disable this by default at some point. @@ -4318,6 +4467,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + if (!Args.hasFlag(options::OPT_Qy, options::OPT_Qn, true)) + CmdArgs.push_back("-Qn"); + // -fcommon is the default unless compiling kernel code or the target says so bool NoCommonDefault = KernelOrKext || isNoCommonDefault(RawTriple); if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common, @@ -4511,31 +4663,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // Setup statistics file output. - if (const Arg *A = Args.getLastArg(options::OPT_save_stats_EQ)) { - StringRef SaveStats = A->getValue(); - - SmallString<128> StatsFile; - bool DoSaveStats = false; - if (SaveStats == "obj") { - if (Output.isFilename()) { - StatsFile.assign(Output.getFilename()); - llvm::sys::path::remove_filename(StatsFile); - } - DoSaveStats = true; - } else if (SaveStats == "cwd") { - DoSaveStats = true; - } else { - D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << SaveStats; - } - - if (DoSaveStats) { - StringRef BaseName = llvm::sys::path::filename(Input.getBaseInput()); - llvm::sys::path::append(StatsFile, BaseName); - llvm::sys::path::replace_extension(StatsFile, "stats"); - CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") + - StatsFile)); - } - } + SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D); + if (!StatsFile.empty()) + CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") + StatsFile)); // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option // parser. @@ -4622,14 +4752,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Flags)); } - // Host-side cuda compilation receives device-side outputs as Inputs[1...]. - // Include them with -fcuda-include-gpubinary. - if (IsCuda && Inputs.size() > 1) - for (auto I = std::next(Inputs.begin()), E = Inputs.end(); I != E; ++I) { + if (IsCuda) { + // Host-side cuda compilation receives all device-side outputs in a single + // fatbin as Inputs[1]. Include the binary with -fcuda-include-gpubinary. + if (Inputs.size() > 1) { + assert(Inputs.size() == 2 && "More than one GPU binary!"); CmdArgs.push_back("-fcuda-include-gpubinary"); - CmdArgs.push_back(I->getFilename()); + CmdArgs.push_back(Inputs[1].getFilename()); } + if (Args.hasFlag(options::OPT_fcuda_rdc, options::OPT_fno_cuda_rdc, false)) + CmdArgs.push_back("-fcuda-rdc"); + if (Args.hasFlag(options::OPT_fcuda_short_ptr, + options::OPT_fno_cuda_short_ptr, false)) + CmdArgs.push_back("-fcuda-short-ptr"); + } + // OpenMP offloading device jobs take the argument -fopenmp-host-ir-file-path // to specify the result of the compile phase on the host, so the meaningful // device declarations can be identified. Also, -fopenmp-is-device is passed @@ -4645,7 +4783,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // For all the host OpenMP offloading compile jobs we need to pass the targets // information using -fopenmp-targets= option. - if (isa<CompileJobAction>(JA) && JA.isHostOffloading(Action::OFK_OpenMP)) { + if (JA.isHostOffloading(Action::OFK_OpenMP)) { SmallString<128> TargetInfo("-fopenmp-targets="); Arg *Tgts = Args.getLastArg(options::OPT_fopenmp_targets_EQ); @@ -4704,6 +4842,40 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + if (Arg *A = Args.getLastArg(options::OPT_fforce_enable_int128, + options::OPT_fno_force_enable_int128)) { + if (A->getOption().matches(options::OPT_fforce_enable_int128)) + CmdArgs.push_back("-fforce-enable-int128"); + } + + if (Args.hasFlag(options::OPT_fcomplete_member_pointers, + options::OPT_fno_complete_member_pointers, false)) + CmdArgs.push_back("-fcomplete-member-pointers"); + + if (Arg *A = Args.getLastArg(options::OPT_moutline, + options::OPT_mno_outline)) { + if (A->getOption().matches(options::OPT_moutline)) { + // We only support -moutline in AArch64 right now. If we're not compiling + // for AArch64, emit a warning and ignore the flag. Otherwise, add the + // proper mllvm flags. + if (Triple.getArch() != llvm::Triple::aarch64) { + D.Diag(diag::warn_drv_moutline_unsupported_opt) << Triple.getArchName(); + } else { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-enable-machine-outliner"); + } + } else { + // Disable all outlining behaviour. + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-enable-machine-outliner=never"); + } + } + + if (Args.hasFlag(options::OPT_faddrsig, options::OPT_fno_addrsig, + getToolChain().getTriple().isOSBinFormatELF() && + getToolChain().useIntegratedAs())) + CmdArgs.push_back("-faddrsig"); + // Finally add the compile command to the compilation. if (Args.hasArg(options::OPT__SLASH_fallback) && Output.getType() == types::TY_Object && @@ -4722,12 +4894,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } - // Handle the debug info splitting at object creation time if we're - // creating an object. - // TODO: Currently only works on linux with newer objcopy. - if (SplitDWARF && Output.getType() == types::TY_Object) - SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDWARFOut); - if (Arg *A = Args.getLastArg(options::OPT_pg)) if (Args.hasArg(options::OPT_fomit_frame_pointer)) D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer" @@ -4778,6 +4944,13 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, getToolChain().getDriver().Diag(diag::err_drv_unknown_objc_runtime) << value; } + if ((runtime.getKind() == ObjCRuntime::GNUstep) && + (runtime.getVersion() >= VersionTuple(2, 0))) + if (!getToolChain().getTriple().isOSBinFormatELF()) { + getToolChain().getDriver().Diag( + diag::err_drv_gnustep_objc_runtime_incompatible_binary) + << runtime.getVersion().getMajor(); + } runtimeArg->render(args, cmdArgs); return runtime; @@ -4871,7 +5044,7 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, // Legacy behaviour is to target the gnustep runtime if we are in // non-fragile mode or the GCC runtime in fragile mode. if (isNonFragile) - runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(1, 6)); + runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(2, 0)); else runtime = ObjCRuntime(ObjCRuntime::GCC, VersionTuple()); } @@ -4999,13 +5172,8 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back("--dependent-lib=oldnames"); } - // Both /showIncludes and /E (and /EP) write to stdout. Allowing both - // would produce interleaved output, so ignore /showIncludes in such cases. - if ((!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_EP)) || - (Args.hasArg(options::OPT__SLASH_P) && - Args.hasArg(options::OPT__SLASH_EP) && !Args.hasArg(options::OPT_E))) - if (Arg *A = Args.getLastArg(options::OPT_show_includes)) - A->render(Args, CmdArgs); + if (Arg *A = Args.getLastArg(options::OPT_show_includes)) + A->render(Args, CmdArgs); // This controls whether or not we emit RTTI data for polymorphic types. if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR, @@ -5135,6 +5303,10 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, else CmdArgs.push_back("msvc"); } + + if (Args.hasArg(options::OPT__SLASH_Guard) && + Args.getLastArgValue(options::OPT__SLASH_Guard).equals_lower("cf")) + CmdArgs.push_back("-cfguard"); } visualstudio::Compiler *Clang::getCLFallback() const { @@ -5289,6 +5461,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // Add the -fdebug-compilation-dir flag if needed. addDebugCompDirArg(Args, CmdArgs); + addDebugPrefixMapArg(getToolChain().getDriver(), Args, CmdArgs); + // Set the AT_producer to the clang version when using the integrated // assembler on assembly source files. CmdArgs.push_back("-dwarf-debug-producer"); @@ -5299,7 +5473,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, } RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion, llvm::DebuggerKind::Default); - RenderDebugInfoCompressionArgs(Args, CmdArgs, D); + RenderDebugInfoCompressionArgs(Args, CmdArgs, D, getToolChain()); // Handle -fPIC et al -- the relocation-model affects the assembler @@ -5385,19 +5559,17 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); + if (Args.hasArg(options::OPT_gsplit_dwarf) && + getToolChain().getTriple().isOSLinux()) { + CmdArgs.push_back("-split-dwarf-file"); + CmdArgs.push_back(SplitDebugName(Args, Input)); + } + assert(Input.isFilename() && "Invalid input."); CmdArgs.push_back(Input.getFilename()); const char *Exec = getToolChain().getDriver().getClangProgramPath(); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); - - // Handle the debug info splitting at object creation time if we're - // creating an object. - // TODO: Currently only works on linux with newer objcopy. - if (Args.hasArg(options::OPT_gsplit_dwarf) && - getToolChain().getTriple().isOSLinux()) - SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, - SplitDebugName(Args, Input)); } // Begin OffloadBundler @@ -5448,6 +5620,10 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, Triples += Action::GetOffloadKindName(CurKind); Triples += '-'; Triples += CurTC->getTriple().normalize(); + if (CurKind == Action::OFK_HIP && CurDep->getOffloadingArch()) { + Triples += '-'; + Triples += CurDep->getOffloadingArch(); + } } CmdArgs.push_back(TCArgs.MakeArgString(Triples)); @@ -5517,6 +5693,11 @@ void OffloadBundler::ConstructJobMultipleOutputs( Triples += Action::GetOffloadKindName(Dep.DependentOffloadKind); Triples += '-'; Triples += Dep.DependentToolChain->getTriple().normalize(); + if (Dep.DependentOffloadKind == Action::OFK_HIP && + !Dep.DependentBoundArch.empty()) { + Triples += '-'; + Triples += Dep.DependentBoundArch; + } } CmdArgs.push_back(TCArgs.MakeArgString(Triples)); diff --git a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp index 49dfeca1b23..66fa21402d7 100644 --- a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp @@ -8,13 +8,14 @@ //===----------------------------------------------------------------------===// #include "Gnu.h" -#include "Linux.h" #include "Arch/ARM.h" #include "Arch/Mips.h" #include "Arch/PPC.h" +#include "Arch/RISCV.h" #include "Arch/Sparc.h" #include "Arch/SystemZ.h" #include "CommonArgs.h" +#include "Linux.h" #include "clang/Basic/VirtualFileSystem.h" #include "clang/Config/config.h" // for GCC_INSTALL_PREFIX #include "clang/Driver/Compilation.h" @@ -84,6 +85,13 @@ void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, A->getOption().matches(options::OPT_W_Group)) continue; + // Don't forward -mno-unaligned-access since GCC doesn't understand + // it and because it doesn't affect the assembly or link steps. + if ((isa<AssembleJobAction>(JA) || isa<LinkJobAction>(JA)) && + (A->getOption().matches(options::OPT_munaligned_access) || + A->getOption().matches(options::OPT_mno_unaligned_access))) + continue; + A->render(Args, CmdArgs); } } @@ -220,35 +228,6 @@ void tools::gcc::Linker::RenderExtraToolArgs(const JobAction &JA, // The types are (hopefully) good enough. } -static bool addXRayRuntime(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { - // Do not add the XRay runtime to shared libraries. - if (Args.hasArg(options::OPT_shared)) - return false; - - if (Args.hasFlag(options::OPT_fxray_instrument, - options::OPT_fnoxray_instrument, false)) { - CmdArgs.push_back("-whole-archive"); - CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray", false)); - CmdArgs.push_back("-no-whole-archive"); - return true; - } - - return false; -} - -static void linkXRayRuntimeDeps(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { - CmdArgs.push_back("--no-as-needed"); - CmdArgs.push_back("-lpthread"); - CmdArgs.push_back("-lrt"); - CmdArgs.push_back("-lm"); - - if (TC.getTriple().getOS() != llvm::Triple::FreeBSD && - TC.getTriple().getOS() != llvm::Triple::NetBSD) - CmdArgs.push_back("-ldl"); -} - static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { switch (T.getArch()) { case llvm::Triple::x86: @@ -258,7 +237,7 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { case llvm::Triple::aarch64: return "aarch64linux"; case llvm::Triple::aarch64_be: - return "aarch64_be_linux"; + return "aarch64linuxb"; case llvm::Triple::arm: case llvm::Triple::thumb: return "armelf_linux_eabi"; @@ -271,6 +250,10 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { return "elf64ppc"; case llvm::Triple::ppc64le: return "elf64lppc"; + case llvm::Triple::riscv32: + return "elf32lriscv"; + case llvm::Triple::riscv64: + return "elf64lriscv"; case llvm::Triple::sparc: case llvm::Triple::sparcel: return "elf32_sparc"; @@ -300,7 +283,8 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { } static bool getPIE(const ArgList &Args, const toolchains::Linux &ToolChain) { - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static)) + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static) || + Args.hasArg(options::OPT_r)) return false; Arg *A = Args.getLastArg(options::OPT_pie, options::OPT_no_pie, @@ -373,9 +357,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, for (const auto &Opt : ToolChain.ExtraOpts) CmdArgs.push_back(Opt.c_str()); - if (!Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("--eh-frame-hdr"); - } + CmdArgs.push_back("--eh-frame-hdr"); if (const char *LDMOption = getLDMOption(ToolChain.getTriple(), Args)) { CmdArgs.push_back("-m"); @@ -453,8 +435,11 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, ToolChain.AddFilePathLibArgs(Args, CmdArgs); - if (D.isUsingLTO()) - AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], + D.getLTOMode() == LTOK_Thin); + } if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); @@ -490,7 +475,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, linkSanitizerRuntimeDeps(ToolChain, CmdArgs); if (NeedsXRayDeps) - linkXRayRuntimeDeps(ToolChain, Args, CmdArgs); + linkXRayRuntimeDeps(ToolChain, CmdArgs); bool WantPthread = Args.hasArg(options::OPT_pthread) || Args.hasArg(options::OPT_pthreads); @@ -550,6 +535,10 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Add OpenMP offloading linker script args if required. AddOpenMPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA); + // Add HIP offloading linker script args if required. + AddHIPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA, + *this); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } @@ -624,6 +613,18 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); break; } + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: { + StringRef ABIName = riscv::getRISCVABI(Args, getToolChain().getTriple()); + CmdArgs.push_back("-mabi"); + CmdArgs.push_back(ABIName.data()); + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { + StringRef MArch = A->getValue(); + CmdArgs.push_back("-march"); + CmdArgs.push_back(MArch.data()); + } + break; + } case llvm::Triple::sparc: case llvm::Triple::sparcel: { CmdArgs.push_back("-32"); @@ -706,11 +707,10 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, if (ABIName != "64" && !Args.hasArg(options::OPT_mno_abicalls)) CmdArgs.push_back("-call_nonpic"); - if (getToolChain().getArch() == llvm::Triple::mips || - getToolChain().getArch() == llvm::Triple::mips64) - CmdArgs.push_back("-EB"); - else + if (getToolChain().getTriple().isLittleEndian()) CmdArgs.push_back("-EL"); + else + CmdArgs.push_back("-EB"); if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) { if (StringRef(A->getValue()) == "2008") @@ -834,14 +834,6 @@ static bool isArmOrThumbArch(llvm::Triple::ArchType Arch) { return Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb; } -static bool isMips32(llvm::Triple::ArchType Arch) { - return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel; -} - -static bool isMips64(llvm::Triple::ArchType Arch) { - return Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el; -} - static bool isMipsEL(llvm::Triple::ArchType Arch) { return Arch == llvm::Triple::mipsel || Arch == llvm::Triple::mips64el; } @@ -856,6 +848,10 @@ static bool isMicroMips(const ArgList &Args) { return A && A->getOption().matches(options::OPT_mmicromips); } +static bool isRISCV(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::riscv32 || Arch == llvm::Triple::riscv64; +} + static Multilib makeMultilib(StringRef commonSuffix) { return Multilib(commonSuffix, commonSuffix, commonSuffix); } @@ -1300,8 +1296,8 @@ bool clang::driver::findMIPSMultilibs(const Driver &D, llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); Multilib::flags_list Flags; - addMultilibFlag(isMips32(TargetArch), "m32", Flags); - addMultilibFlag(isMips64(TargetArch), "m64", Flags); + addMultilibFlag(TargetTriple.isMIPS32(), "m32", Flags); + addMultilibFlag(TargetTriple.isMIPS64(), "m64", Flags); addMultilibFlag(isMips16(Args), "mips16", Flags); addMultilibFlag(CPUName == "mips32", "march=mips32", Flags); addMultilibFlag(CPUName == "mips32r2" || CPUName == "mips32r3" || @@ -1401,11 +1397,48 @@ static void findAndroidArmMultilibs(const Driver &D, Result.Multilibs = AndroidArmMultilibs; } +static void findRISCVMultilibs(const Driver &D, + const llvm::Triple &TargetTriple, StringRef Path, + const ArgList &Args, DetectedMultilibs &Result) { + + FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); + Multilib Ilp32 = makeMultilib("lib32/ilp32").flag("+m32").flag("+mabi=ilp32"); + Multilib Ilp32f = + makeMultilib("lib32/ilp32f").flag("+m32").flag("+mabi=ilp32f"); + Multilib Ilp32d = + makeMultilib("lib32/ilp32d").flag("+m32").flag("+mabi=ilp32d"); + Multilib Lp64 = makeMultilib("lib64/lp64").flag("+m64").flag("+mabi=lp64"); + Multilib Lp64f = makeMultilib("lib64/lp64f").flag("+m64").flag("+mabi=lp64f"); + Multilib Lp64d = makeMultilib("lib64/lp64d").flag("+m64").flag("+mabi=lp64d"); + MultilibSet RISCVMultilibs = + MultilibSet() + .Either({Ilp32, Ilp32f, Ilp32d, Lp64, Lp64f, Lp64d}) + .FilterOut(NonExistent); + + Multilib::flags_list Flags; + bool IsRV64 = TargetTriple.getArch() == llvm::Triple::riscv64; + StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple); + + addMultilibFlag(!IsRV64, "m32", Flags); + addMultilibFlag(IsRV64, "m64", Flags); + addMultilibFlag(ABIName == "ilp32", "mabi=ilp32", Flags); + addMultilibFlag(ABIName == "ilp32f", "mabi=ilp32f", Flags); + addMultilibFlag(ABIName == "ilp32d", "mabi=ilp32d", Flags); + addMultilibFlag(ABIName == "lp64", "mabi=lp64", Flags); + addMultilibFlag(ABIName == "lp64f", "mabi=lp64f", Flags); + addMultilibFlag(ABIName == "lp64d", "mabi=lp64d", Flags); + + if (RISCVMultilibs.select(Flags, Result.SelectedMultilib)) + Result.Multilibs = RISCVMultilibs; +} + static bool findBiarchMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, bool NeedsBiarchSuffix, DetectedMultilibs &Result) { + Multilib Default; + // Some versions of SUSE and Fedora on ppc64 put 32-bit libs // in what would normally be GCCInstallPath and put the 64-bit // libs in a subdirectory named 64. The simple logic we follow is that @@ -1413,10 +1446,26 @@ static bool findBiarchMultilibs(const Driver &D, // we use that. If not, and if not a biarch triple alias, we look for // crtbegin.o without the subdirectory. - Multilib Default; + StringRef Suff64 = "/64"; + // Solaris uses platform-specific suffixes instead of /64. + if (TargetTriple.getOS() == llvm::Triple::Solaris) { + switch (TargetTriple.getArch()) { + case llvm::Triple::x86: + case llvm::Triple::x86_64: + Suff64 = "/amd64"; + break; + case llvm::Triple::sparc: + case llvm::Triple::sparcv9: + Suff64 = "/sparcv9"; + break; + default: + break; + } + } + Multilib Alt64 = Multilib() - .gccSuffix("/64") - .includeSuffix("/64") + .gccSuffix(Suff64) + .includeSuffix(Suff64) .flag("-m32") .flag("+m64") .flag("-mx32"); @@ -1491,7 +1540,7 @@ static bool findBiarchMultilibs(const Driver &D, /// all subcommands; this relies on gcc translating the majority of /// command line options. -/// \brief Less-than for GCCVersion, implementing a Strict Weak Ordering. +/// Less-than for GCCVersion, implementing a Strict Weak Ordering. bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor, int RHSPatch, StringRef RHSPatchSuffix) const { @@ -1525,7 +1574,7 @@ bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor, return false; } -/// \brief Parse a GCCVersion object out of a string of text. +/// Parse a GCCVersion object out of a string of text. /// /// This is the primary means of forming GCCVersion objects. /*static*/ @@ -1540,21 +1589,29 @@ Generic_GCC::GCCVersion Generic_GCC::GCCVersion::Parse(StringRef VersionText) { GoodVersion.MajorStr = First.first.str(); if (First.second.empty()) return GoodVersion; - if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0) + StringRef MinorStr = Second.first; + if (Second.second.empty()) { + if (size_t EndNumber = MinorStr.find_first_not_of("0123456789")) { + GoodVersion.PatchSuffix = MinorStr.substr(EndNumber); + MinorStr = MinorStr.slice(0, EndNumber); + } + } + if (MinorStr.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0) return BadVersion; - GoodVersion.MinorStr = Second.first.str(); + GoodVersion.MinorStr = MinorStr.str(); // First look for a number prefix and parse that if present. Otherwise just // stash the entire patch string in the suffix, and leave the number // unspecified. This covers versions strings such as: // 5 (handled above) // 4.4 + // 4.4-patched // 4.4.0 // 4.4.x // 4.4.2-rc4 // 4.4.x-patched // And retains any patch number it finds. - StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str(); + StringRef PatchText = Second.second; if (!PatchText.empty()) { if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) { // Try to parse the number and any suffix. @@ -1575,7 +1632,7 @@ static llvm::StringRef getGCCToolchainDir(const ArgList &Args) { return GCC_INSTALL_PREFIX; } -/// \brief Initialize a GCCInstallationDetector from the driver. +/// Initialize a GCCInstallationDetector from the driver. /// /// This performs all of the autodetection and sets up the various paths. /// Once constructed, a GCCInstallationDetector is essentially immutable. @@ -1613,21 +1670,17 @@ void Generic_GCC::GCCInstallationDetector::init( // If we have a SysRoot, try that first. if (!D.SysRoot.empty()) { Prefixes.push_back(D.SysRoot); - Prefixes.push_back(D.SysRoot + "/usr"); + AddDefaultGCCPrefixes(TargetTriple, Prefixes, D.SysRoot); } // Then look for gcc installed alongside clang. Prefixes.push_back(D.InstalledDir + "/.."); - // Then look for distribution supplied gcc installations. + // Next, look for prefix(es) that correspond to distribution-supplied gcc + // installations. if (D.SysRoot.empty()) { - // Look for RHEL devtoolsets. - Prefixes.push_back("/opt/rh/devtoolset-6/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-4/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-3/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-2/root/usr"); - // And finally in /usr. - Prefixes.push_back("/usr"); + // Typically /usr. + AddDefaultGCCPrefixes(TargetTriple, Prefixes, D.SysRoot); } } @@ -1636,18 +1689,21 @@ void Generic_GCC::GCCInstallationDetector::init( // in /usr. This avoids accidentally enforcing the system GCC version // when using a custom toolchain. if (GCCToolchainDir == "" || GCCToolchainDir == D.SysRoot + "/usr") { - for (StringRef CandidateTriple : ExtraTripleAliases) { - if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) - return; - } - for (StringRef CandidateTriple : CandidateTripleAliases) { - if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) - return; - } - for (StringRef CandidateTriple : CandidateBiarchTripleAliases) { - if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple, true)) - return; - } + SmallVector<StringRef, 16> GentooTestTriples; + // Try to match an exact triple as target triple first. + // e.g. crossdev -S x86_64-gentoo-linux-gnu will install gcc libs for + // x86_64-gentoo-linux-gnu. But "clang -target x86_64-gentoo-linux-gnu" + // may pick the libraries for x86_64-pc-linux-gnu even when exact matching + // triple x86_64-gentoo-linux-gnu is present. + GentooTestTriples.push_back(TargetTriple.str()); + // Check rest of triples. + GentooTestTriples.append(ExtraTripleAliases.begin(), + ExtraTripleAliases.end()); + GentooTestTriples.append(CandidateTripleAliases.begin(), + CandidateTripleAliases.end()); + if (ScanGentooConfigs(TargetTriple, Args, GentooTestTriples, + CandidateBiarchTripleAliases)) + return; } // Loop over the various components which exist and select the best GCC @@ -1660,6 +1716,9 @@ void Generic_GCC::GCCInstallationDetector::init( const std::string LibDir = Prefix + Suffix.str(); if (!D.getVFS().exists(LibDir)) continue; + // Try to match the exact target triple first. + ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, TargetTriple.str()); + // Try rest of possible triples. for (StringRef Candidate : ExtraTripleAliases) // Try these first. ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); for (StringRef Candidate : CandidateTripleAliases) @@ -1698,6 +1757,49 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { return false; } +void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( + const llvm::Triple &TargetTriple, SmallVectorImpl<std::string> &Prefixes, + StringRef SysRoot) { + if (TargetTriple.getOS() == llvm::Triple::Solaris) { + // Solaris is a special case. + // The GCC installation is under + // /usr/gcc/<major>.<minor>/lib/gcc/<triple>/<major>.<minor>.<patch>/ + // so we need to find those /usr/gcc/*/lib/gcc libdirs and go with + // /usr/gcc/<version> as a prefix. + + std::string PrefixDir = SysRoot.str() + "/usr/gcc"; + std::error_code EC; + for (vfs::directory_iterator LI = D.getVFS().dir_begin(PrefixDir, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->getName()); + GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); + + // Filter out obviously bad entries. + if (CandidateVersion.Major == -1 || CandidateVersion.isOlderThan(4, 1, 1)) + continue; + + std::string CandidatePrefix = PrefixDir + "/" + VersionText.str(); + std::string CandidateLibPath = CandidatePrefix + "/lib/gcc"; + if (!D.getVFS().exists(CandidateLibPath)) + continue; + + Prefixes.push_back(CandidatePrefix); + } + return; + } + + // Non-Solaris is much simpler - most systems just go with "/usr". + if (SysRoot.empty() && TargetTriple.getOS() == llvm::Triple::Linux) { + // Yet, still look for RHEL devtoolsets. + Prefixes.push_back("/opt/rh/devtoolset-7/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-6/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-4/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-3/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-2/root/usr"); + } + Prefixes.push_back(SysRoot.str() + "/usr"); +} + /*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples( const llvm::Triple &TargetTriple, const llvm::Triple &BiarchTriple, SmallVectorImpl<StringRef> &LibDirs, @@ -1709,22 +1811,20 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { // lifetime or initialization issues. static const char *const AArch64LibDirs[] = {"/lib64", "/lib"}; static const char *const AArch64Triples[] = { - "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-linux-android", - "aarch64-redhat-linux", "aarch64-suse-linux"}; + "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-redhat-linux", + "aarch64-suse-linux"}; static const char *const AArch64beLibDirs[] = {"/lib"}; static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu", "aarch64_be-linux-gnu"}; static const char *const ARMLibDirs[] = {"/lib"}; - static const char *const ARMTriples[] = {"arm-linux-gnueabi", - "arm-linux-androideabi"}; + static const char *const ARMTriples[] = {"arm-linux-gnueabi"}; static const char *const ARMHFTriples[] = {"arm-linux-gnueabihf", "armv7hl-redhat-linux-gnueabi", "armv6hl-suse-linux-gnueabi", "armv7hl-suse-linux-gnueabi"}; static const char *const ARMebLibDirs[] = {"/lib"}; - static const char *const ARMebTriples[] = {"armeb-linux-gnueabi", - "armeb-linux-androideabi"}; + static const char *const ARMebTriples[] = {"armeb-linux-gnueabi"}; static const char *const ARMebHFTriples[] = { "armeb-linux-gnueabihf", "armebv7hl-redhat-linux-gnueabi"}; @@ -1734,16 +1834,15 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { "x86_64-pc-linux-gnu", "x86_64-redhat-linux6E", "x86_64-redhat-linux", "x86_64-suse-linux", "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", - "x86_64-slackware-linux", "x86_64-linux-android", - "x86_64-unknown-linux"}; + "x86_64-slackware-linux", "x86_64-unknown-linux", + "x86_64-amazon-linux"}; static const char *const X32LibDirs[] = {"/libx32"}; static const char *const X86LibDirs[] = {"/lib32", "/lib"}; static const char *const X86Triples[] = { "i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu", "i386-linux-gnu", "i386-redhat-linux6E", "i686-redhat-linux", "i586-redhat-linux", "i386-redhat-linux", "i586-suse-linux", - "i486-slackware-linux", "i686-montavista-linux", "i686-linux-android", - "i586-linux-gnu"}; + "i486-slackware-linux", "i686-montavista-linux", "i586-linux-gnu"}; static const char *const MIPSLibDirs[] = {"/lib"}; static const char *const MIPSTriples[] = {"mips-linux-gnu", "mips-mti-linux", @@ -1762,13 +1861,6 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { "mips64el-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu", "mips64el-linux-gnuabi64"}; - static const char *const MIPSELAndroidLibDirs[] = {"/lib", "/libr2", - "/libr6"}; - static const char *const MIPSELAndroidTriples[] = {"mipsel-linux-android"}; - static const char *const MIPS64ELAndroidLibDirs[] = {"/lib64", "/lib", - "/libr2", "/libr6"}; - static const char *const MIPS64ELAndroidTriples[] = { - "mips64el-linux-android"}; static const char *const PPCLibDirs[] = {"/lib32", "/lib"}; static const char *const PPCTriples[] = { @@ -1783,6 +1875,11 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { "powerpc64le-linux-gnu", "powerpc64le-unknown-linux-gnu", "powerpc64le-suse-linux", "ppc64le-redhat-linux"}; + static const char *const RISCV32LibDirs[] = {"/lib", "/lib32"}; + static const char *const RISCVTriples[] = {"riscv32-unknown-linux-gnu", + "riscv64-unknown-linux-gnu", + "riscv32-unknown-elf"}; + static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"}; static const char *const SPARCv8Triples[] = {"sparc-linux-gnu", "sparcv8-linux-gnu"}; @@ -1795,17 +1892,109 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu", "s390x-suse-linux", "s390x-redhat-linux"}; - // Solaris. - static const char *const SolarisSPARCLibDirs[] = {"/gcc"}; - static const char *const SolarisSPARCTriples[] = {"sparc-sun-solaris2.11", - "i386-pc-solaris2.11"}; using std::begin; using std::end; if (TargetTriple.getOS() == llvm::Triple::Solaris) { - LibDirs.append(begin(SolarisSPARCLibDirs), end(SolarisSPARCLibDirs)); - TripleAliases.append(begin(SolarisSPARCTriples), end(SolarisSPARCTriples)); + static const char *const SolarisLibDirs[] = {"/lib"}; + static const char *const SolarisSparcV8Triples[] = { + "sparc-sun-solaris2.11", "sparc-sun-solaris2.12"}; + static const char *const SolarisSparcV9Triples[] = { + "sparcv9-sun-solaris2.11", "sparcv9-sun-solaris2.12"}; + static const char *const SolarisX86Triples[] = {"i386-pc-solaris2.11", + "i386-pc-solaris2.12"}; + static const char *const SolarisX86_64Triples[] = {"x86_64-pc-solaris2.11", + "x86_64-pc-solaris2.12"}; + LibDirs.append(begin(SolarisLibDirs), end(SolarisLibDirs)); + BiarchLibDirs.append(begin(SolarisLibDirs), end(SolarisLibDirs)); + switch (TargetTriple.getArch()) { + case llvm::Triple::x86: + TripleAliases.append(begin(SolarisX86Triples), end(SolarisX86Triples)); + BiarchTripleAliases.append(begin(SolarisX86_64Triples), + end(SolarisX86_64Triples)); + break; + case llvm::Triple::x86_64: + TripleAliases.append(begin(SolarisX86_64Triples), + end(SolarisX86_64Triples)); + BiarchTripleAliases.append(begin(SolarisX86Triples), + end(SolarisX86Triples)); + break; + case llvm::Triple::sparc: + TripleAliases.append(begin(SolarisSparcV8Triples), + end(SolarisSparcV8Triples)); + BiarchTripleAliases.append(begin(SolarisSparcV9Triples), + end(SolarisSparcV9Triples)); + break; + case llvm::Triple::sparcv9: + TripleAliases.append(begin(SolarisSparcV9Triples), + end(SolarisSparcV9Triples)); + BiarchTripleAliases.append(begin(SolarisSparcV8Triples), + end(SolarisSparcV8Triples)); + break; + default: + break; + } + return; + } + + // Android targets should not use GNU/Linux tools or libraries. + if (TargetTriple.isAndroid()) { + static const char *const AArch64AndroidTriples[] = { + "aarch64-linux-android"}; + static const char *const ARMAndroidTriples[] = {"arm-linux-androideabi"}; + static const char *const MIPSELAndroidTriples[] = {"mipsel-linux-android"}; + static const char *const MIPS64ELAndroidTriples[] = { + "mips64el-linux-android"}; + static const char *const X86AndroidTriples[] = {"i686-linux-android"}; + static const char *const X86_64AndroidTriples[] = {"x86_64-linux-android"}; + + switch (TargetTriple.getArch()) { + case llvm::Triple::aarch64: + LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); + TripleAliases.append(begin(AArch64AndroidTriples), + end(AArch64AndroidTriples)); + break; + case llvm::Triple::arm: + case llvm::Triple::thumb: + LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs)); + TripleAliases.append(begin(ARMAndroidTriples), end(ARMAndroidTriples)); + break; + case llvm::Triple::mipsel: + LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); + TripleAliases.append(begin(MIPSELAndroidTriples), + end(MIPSELAndroidTriples)); + BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); + BiarchTripleAliases.append(begin(MIPS64ELAndroidTriples), + end(MIPS64ELAndroidTriples)); + break; + case llvm::Triple::mips64el: + LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); + TripleAliases.append(begin(MIPS64ELAndroidTriples), + end(MIPS64ELAndroidTriples)); + BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); + BiarchTripleAliases.append(begin(MIPSELAndroidTriples), + end(MIPSELAndroidTriples)); + break; + case llvm::Triple::x86_64: + LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); + TripleAliases.append(begin(X86_64AndroidTriples), + end(X86_64AndroidTriples)); + BiarchLibDirs.append(begin(X86LibDirs), end(X86LibDirs)); + BiarchTripleAliases.append(begin(X86AndroidTriples), + end(X86AndroidTriples)); + break; + case llvm::Triple::x86: + LibDirs.append(begin(X86LibDirs), end(X86LibDirs)); + TripleAliases.append(begin(X86AndroidTriples), end(X86AndroidTriples)); + BiarchLibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); + BiarchTripleAliases.append(begin(X86_64AndroidTriples), + end(X86_64AndroidTriples)); + break; + default: + break; + } + return; } @@ -1870,22 +2059,11 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { BiarchTripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples)); break; case llvm::Triple::mipsel: - if (TargetTriple.isAndroid()) { - LibDirs.append(begin(MIPSELAndroidLibDirs), end(MIPSELAndroidLibDirs)); - TripleAliases.append(begin(MIPSELAndroidTriples), - end(MIPSELAndroidTriples)); - BiarchLibDirs.append(begin(MIPS64ELAndroidLibDirs), - end(MIPS64ELAndroidLibDirs)); - BiarchTripleAliases.append(begin(MIPS64ELAndroidTriples), - end(MIPS64ELAndroidTriples)); - - } else { - LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); - TripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); - TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); - BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); - BiarchTripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); - } + LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); + TripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); + TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); + BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); + BiarchTripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); break; case llvm::Triple::mips64: LibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs)); @@ -1894,23 +2072,11 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); break; case llvm::Triple::mips64el: - if (TargetTriple.isAndroid()) { - LibDirs.append(begin(MIPS64ELAndroidLibDirs), - end(MIPS64ELAndroidLibDirs)); - TripleAliases.append(begin(MIPS64ELAndroidTriples), - end(MIPS64ELAndroidTriples)); - BiarchLibDirs.append(begin(MIPSELAndroidLibDirs), - end(MIPSELAndroidLibDirs)); - BiarchTripleAliases.append(begin(MIPSELAndroidTriples), - end(MIPSELAndroidTriples)); - - } else { - LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); - TripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); - BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); - BiarchTripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); - BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); - } + LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); + TripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); + BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); + BiarchTripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); + BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); break; case llvm::Triple::ppc: LibDirs.append(begin(PPCLibDirs), end(PPCLibDirs)); @@ -1928,6 +2094,12 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { LibDirs.append(begin(PPC64LELibDirs), end(PPC64LELibDirs)); TripleAliases.append(begin(PPC64LETriples), end(PPC64LETriples)); break; + case llvm::Triple::riscv32: + LibDirs.append(begin(RISCV32LibDirs), end(RISCV32LibDirs)); + BiarchLibDirs.append(begin(RISCV32LibDirs), end(RISCV32LibDirs)); + TripleAliases.append(begin(RISCVTriples), end(RISCVTriples)); + BiarchTripleAliases.append(begin(RISCVTriples), end(RISCVTriples)); + break; case llvm::Triple::sparc: case llvm::Triple::sparcel: LibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs)); @@ -1960,56 +2132,6 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { BiarchTripleAliases.push_back(BiarchTriple.str()); } -void Generic_GCC::GCCInstallationDetector::scanLibDirForGCCTripleSolaris( - const llvm::Triple &TargetArch, const llvm::opt::ArgList &Args, - const std::string &LibDir, StringRef CandidateTriple, - bool NeedsBiarchSuffix) { - // Solaris is a special case. The GCC installation is under - // /usr/gcc/<major>.<minor>/lib/gcc/<triple>/<major>.<minor>.<patch>/, so we - // need to iterate twice. - std::error_code EC; - for (vfs::directory_iterator LI = D.getVFS().dir_begin(LibDir, EC), LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->getName()); - GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); - - if (CandidateVersion.Major != -1) // Filter obviously bad entries. - if (!CandidateGCCInstallPaths.insert(LI->getName()).second) - continue; // Saw this path before; no need to look at it again. - if (CandidateVersion.isOlderThan(4, 1, 1)) - continue; - if (CandidateVersion <= Version) - continue; - - GCCInstallPath = - LibDir + "/" + VersionText.str() + "/lib/gcc/" + CandidateTriple.str(); - if (!D.getVFS().exists(GCCInstallPath)) - continue; - - // If we make it here there has to be at least one GCC version, let's just - // use the latest one. - std::error_code EEC; - for (vfs::directory_iterator - LLI = D.getVFS().dir_begin(GCCInstallPath, EEC), - LLE; - !EEC && LLI != LLE; LLI = LLI.increment(EEC)) { - - StringRef SubVersionText = llvm::sys::path::filename(LLI->getName()); - GCCVersion CandidateSubVersion = GCCVersion::Parse(SubVersionText); - - if (CandidateSubVersion > Version) - Version = CandidateSubVersion; - } - - GCCTriple.setTriple(CandidateTriple); - - GCCInstallPath += "/" + Version.Text; - GCCParentLibPath = GCCInstallPath + "/../../../../"; - - IsValid = true; - } -} - bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( const llvm::Triple &TargetTriple, const ArgList &Args, StringRef Path, bool NeedsBiarchSuffix) { @@ -2022,9 +2144,11 @@ bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( if (isArmOrThumbArch(TargetArch) && TargetTriple.isAndroid()) { // It should also work without multilibs in a simplified toolchain. findAndroidArmMultilibs(D, TargetTriple, Path, Args, Detected); - } else if (tools::isMipsArch(TargetArch)) { + } else if (TargetTriple.isMIPS()) { if (!findMIPSMultilibs(D, TargetTriple, Path, Args, Detected)) return false; + } else if (isRISCV(TargetArch)) { + findRISCVMultilibs(D, TargetTriple, Path, Args, Detected); } else if (!findBiarchMultilibs(D, TargetTriple, Path, Args, NeedsBiarchSuffix, Detected)) { return false; @@ -2041,12 +2165,6 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( const llvm::Triple &TargetTriple, const ArgList &Args, const std::string &LibDir, StringRef CandidateTriple, bool NeedsBiarchSuffix) { - if (TargetTriple.getOS() == llvm::Triple::Solaris) { - scanLibDirForGCCTripleSolaris(TargetTriple, Args, LibDir, CandidateTriple, - NeedsBiarchSuffix); - return; - } - llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); // Locations relative to the system lib directory where GCC's triple-specific // directories might reside. @@ -2059,31 +2177,34 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( // Whether this library suffix is relevant for the triple. bool Active; } Suffixes[] = { - // This is the normal place. - {"gcc/" + CandidateTriple.str(), "../..", true}, - - // Debian puts cross-compilers in gcc-cross. - {"gcc-cross/" + CandidateTriple.str(), "../..", true}, - - // The Freescale PPC SDK has the gcc libraries in - // <sysroot>/usr/lib/<triple>/x.y.z so have a look there as well. Only do - // this on Freescale triples, though, since some systems put a *lot* of - // files in that location, not just GCC installation data. - {CandidateTriple.str(), "..", - TargetTriple.getVendor() == llvm::Triple::Freescale}, - - // Natively multiarch systems sometimes put the GCC triple-specific - // directory within their multiarch lib directory, resulting in the - // triple appearing twice. - {CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), "../../..", true}, - - // Deal with cases (on Ubuntu) where the system architecture could be i386 - // but the GCC target architecture could be (say) i686. - // FIXME: It may be worthwhile to generalize this and look for a second - // triple. - {"i386-linux-gnu/gcc/" + CandidateTriple.str(), "../../..", - TargetArch == llvm::Triple::x86} - }; + // This is the normal place. + {"gcc/" + CandidateTriple.str(), "../..", true}, + + // Debian puts cross-compilers in gcc-cross. + {"gcc-cross/" + CandidateTriple.str(), "../..", + TargetTriple.getOS() != llvm::Triple::Solaris}, + + // The Freescale PPC SDK has the gcc libraries in + // <sysroot>/usr/lib/<triple>/x.y.z so have a look there as well. Only do + // this on Freescale triples, though, since some systems put a *lot* of + // files in that location, not just GCC installation data. + {CandidateTriple.str(), "..", + TargetTriple.getVendor() == llvm::Triple::Freescale || + TargetTriple.getVendor() == llvm::Triple::OpenEmbedded}, + + // Natively multiarch systems sometimes put the GCC triple-specific + // directory within their multiarch lib directory, resulting in the + // triple appearing twice. + {CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), "../../..", + TargetTriple.getOS() != llvm::Triple::Solaris}, + + // Deal with cases (on Ubuntu) where the system architecture could be i386 + // but the GCC target architecture could be (say) i686. + // FIXME: It may be worthwhile to generalize this and look for a second + // triple. + {"i386-linux-gnu/gcc/" + CandidateTriple.str(), "../../..", + (TargetArch == llvm::Triple::x86 && + TargetTriple.getOS() != llvm::Triple::Solaris)}}; for (auto &Suffix : Suffixes) { if (!Suffix.Active) @@ -2121,6 +2242,22 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( } } +bool Generic_GCC::GCCInstallationDetector::ScanGentooConfigs( + const llvm::Triple &TargetTriple, const ArgList &Args, + const SmallVectorImpl<StringRef> &CandidateTriples, + const SmallVectorImpl<StringRef> &CandidateBiarchTriples) { + for (StringRef CandidateTriple : CandidateTriples) { + if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) + return true; + } + + for (StringRef CandidateTriple : CandidateBiarchTriples) { + if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple, true)) + return true; + } + return false; +} + bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( const llvm::Triple &TargetTriple, const ArgList &Args, StringRef CandidateTriple, bool NeedsBiarchSuffix) { @@ -2133,23 +2270,53 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( for (StringRef Line : Lines) { Line = Line.trim(); // CURRENT=triple-version - if (Line.consume_front("CURRENT=")) { - const std::pair<StringRef, StringRef> ActiveVersion = - Line.rsplit('-'); - // Note: Strictly speaking, we should be reading - // /etc/env.d/gcc/${CURRENT} now. However, the file doesn't - // contain anything new or especially useful to us. - const std::string GentooPath = D.SysRoot + "/usr/lib/gcc/" + - ActiveVersion.first.str() + "/" + - ActiveVersion.second.str(); + if (!Line.consume_front("CURRENT=")) + continue; + // Process the config file pointed to by CURRENT. + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ConfigFile = + D.getVFS().getBufferForFile(D.SysRoot + "/etc/env.d/gcc/" + + Line.str()); + std::pair<StringRef, StringRef> ActiveVersion = Line.rsplit('-'); + // List of paths to scan for libraries. + SmallVector<StringRef, 4> GentooScanPaths; + // Scan the Config file to find installed GCC libraries path. + // Typical content of the GCC config file: + // LDPATH="/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.x:/usr/lib/gcc/ + // (continued from previous line) x86_64-pc-linux-gnu/4.9.x/32" + // MANPATH="/usr/share/gcc-data/x86_64-pc-linux-gnu/4.9.x/man" + // INFOPATH="/usr/share/gcc-data/x86_64-pc-linux-gnu/4.9.x/info" + // STDCXX_INCDIR="/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.x/include/g++-v4" + // We are looking for the paths listed in LDPATH=... . + if (ConfigFile) { + SmallVector<StringRef, 2> ConfigLines; + ConfigFile.get()->getBuffer().split(ConfigLines, "\n"); + for (StringRef ConfLine : ConfigLines) { + ConfLine = ConfLine.trim(); + if (ConfLine.consume_front("LDPATH=")) { + // Drop '"' from front and back if present. + ConfLine.consume_back("\""); + ConfLine.consume_front("\""); + // Get all paths sperated by ':' + ConfLine.split(GentooScanPaths, ':', -1, /*AllowEmpty*/ false); + } + } + } + // Test the path based on the version in /etc/env.d/gcc/config-{tuple}. + std::string basePath = "/usr/lib/gcc/" + ActiveVersion.first.str() + "/" + + ActiveVersion.second.str(); + GentooScanPaths.push_back(StringRef(basePath)); + + // Scan all paths for GCC libraries. + for (const auto &GentooScanPath : GentooScanPaths) { + std::string GentooPath = D.SysRoot + std::string(GentooScanPath); if (D.getVFS().exists(GentooPath + "/crtbegin.o")) { if (!ScanGCCForMultilibs(TargetTriple, Args, GentooPath, NeedsBiarchSuffix)) - return false; + continue; Version = GCCVersion::Parse(ActiveVersion.second); GCCInstallPath = GentooPath; - GCCParentLibPath = GentooPath + "/../../.."; + GCCParentLibPath = GentooPath + std::string("/../../.."); GCCTriple.setTriple(ActiveVersion.first); IsValid = true; return true; @@ -2240,6 +2407,8 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const { case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: case llvm::Triple::systemz: case llvm::Triple::mips: case llvm::Triple::mipsel: @@ -2267,12 +2436,9 @@ void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, return; switch (GetCXXStdlibType(DriverArgs)) { - case ToolChain::CST_Libcxx: { - std::string Path = findLibCxxIncludePath(); - if (!Path.empty()) - addSystemInclude(DriverArgs, CC1Args, Path); + case ToolChain::CST_Libcxx: + addLibCxxIncludePaths(DriverArgs, CC1Args); break; - } case ToolChain::CST_Libstdcxx: addLibStdCxxIncludePaths(DriverArgs, CC1Args); @@ -2280,9 +2446,12 @@ void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, } } -std::string Generic_GCC::findLibCxxIncludePath() const { +void +Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { // FIXME: The Linux behavior would probaby be a better approach here. - return getDriver().SysRoot + "/usr/include/c++/v1"; + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/c++/v1"); } void @@ -2292,7 +2461,7 @@ Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, // FIXME: If we have a valid GCCInstallation, use it. } -/// \brief Helper to add the variant paths of a libstdc++ installation. +/// Helper to add the variant paths of a libstdc++ installation. bool Generic_GCC::addLibStdCXXIncludePaths( Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple, StringRef TargetMultiarchTriple, Twine IncludeSuffix, @@ -2377,6 +2546,8 @@ void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, bool UseInitArrayDefault = getTriple().getArch() == llvm::Triple::aarch64 || getTriple().getArch() == llvm::Triple::aarch64_be || + (getTriple().getOS() == llvm::Triple::FreeBSD && + getTriple().getOSMajorVersion() >= 12) || (getTriple().getOS() == llvm::Triple::Linux && ((!GCCInstallation.isValid() || !V.isOlderThan(4, 7, 0)) || getTriple().isAndroid())) || diff --git a/gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.cpp b/gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.cpp index ca8321c2474..e199c38966b 100644 --- a/gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.cpp +++ b/gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.cpp @@ -15,6 +15,7 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" #include "llvm/Option/ArgList.h" using namespace clang::driver; @@ -69,10 +70,10 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mabi"); CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); - if (getToolChain().getArch() == llvm::Triple::mips64) - CmdArgs.push_back("-EB"); - else + if (getToolChain().getTriple().isLittleEndian()) CmdArgs.push_back("-EL"); + else + CmdArgs.push_back("-EB"); AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; @@ -99,6 +100,8 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const toolchains::OpenBSD &ToolChain = + static_cast<const toolchains::OpenBSD &>(getToolChain()); const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; @@ -137,7 +140,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_pie)) CmdArgs.push_back("-pie"); - if (Args.hasArg(options::OPT_nopie)) + if (Args.hasArg(options::OPT_nopie) || Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-nopie"); if (Output.isFilename()) { @@ -174,6 +177,8 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_s, options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); + bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); + bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { @@ -185,7 +190,14 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("-lm"); } - + if (NeedsSanitizerDeps) { + CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins", false)); + linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + } + if (NeedsXRayDeps) { + CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins", false)); + linkXRayRuntimeDeps(ToolChain, CmdArgs); + } // FIXME: For some reason GCC passes -lgcc before adding // the default system libraries. Just mimic this for now. CmdArgs.push_back("-lcompiler_rt"); @@ -216,10 +228,28 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.MakeArgString(getToolChain().GetFilePath("crtendS.o"))); } - const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); + const char *Exec = Args.MakeArgString( + !NeedsSanitizerDeps ? getToolChain().GetLinkerPath() + : getToolChain().GetProgramPath("ld.lld")); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } +SanitizerMask OpenBSD::getSupportedSanitizers() const { + const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; + const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; + + // For future use, only UBsan at the moment + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + + if (IsX86 || IsX86_64) { + Res |= SanitizerKind::Vptr; + Res |= SanitizerKind::Fuzzer; + Res |= SanitizerKind::FuzzerNoLink; + } + + return Res; +} + /// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly. OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple, @@ -276,14 +306,16 @@ void OpenBSD::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - switch (GetCXXStdlibType(Args)) { + bool Profiling = Args.hasArg(options::OPT_pg); + + switch (GetCXXStdlibType(Args)) { case ToolChain::CST_Libcxx: - CmdArgs.push_back("-lc++"); - CmdArgs.push_back("-lc++abi"); - CmdArgs.push_back("-lpthread"); + CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); + CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi"); + CmdArgs.push_back(Profiling ? "-lpthread_p" : "-lpthread"); break; case ToolChain::CST_Libstdcxx: - CmdArgs.push_back("-lstdc++"); + CmdArgs.push_back(Profiling ? "-lstdc++_p" : "-lstdc++"); break; } } diff --git a/gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.h b/gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.h index 750c87b58d8..1aba4de44c5 100644 --- a/gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.h +++ b/gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.h @@ -58,19 +58,21 @@ public: bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } bool isPIEDefault() const override { return true; } + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { return 2; } unsigned GetDefaultDwarfVersion() const override { return 2; } + SanitizerMask getSupportedSanitizers() const override; + protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; diff --git a/gnu/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp b/gnu/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp index a637af723ab..de089ad0c17 100644 --- a/gnu/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp +++ b/gnu/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp @@ -1,4 +1,4 @@ -//===--- CompilerInvocation.cpp -------------------------------------------===// +//===- CompilerInvocation.cpp ---------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -10,54 +10,99 @@ #include "clang/Frontend/CompilerInvocation.h" #include "TestModuleFileExtension.h" #include "clang/Basic/Builtins.h" -#include "clang/Basic/FileManager.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/CommentOptions.h" +#include "clang/Basic/DebugInfoOptions.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileSystemOptions.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/Sanitizers.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TargetOptions.h" #include "clang/Basic/Version.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Basic/Visibility.h" +#include "clang/Basic/XRayInstr.h" #include "clang/Config/config.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" -#include "clang/Driver/Util.h" +#include "clang/Frontend/CodeGenOptions.h" +#include "clang/Frontend/CommandLineSourceLoc.h" +#include "clang/Frontend/DependencyOutputOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/LangStandard.h" +#include "clang/Frontend/MigratorOptions.h" +#include "clang/Frontend/PreprocessorOutputOptions.h" #include "clang/Frontend/Utils.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/PreprocessorOptions.h" -#include "clang/Serialization/ASTReader.h" +#include "clang/Sema/CodeCompleteOptions.h" #include "clang/Serialization/ModuleFileExtension.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/Hashing.h" -#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" +#include "llvm/ADT/Twine.h" #include "llvm/Linker/Linker.h" +#include "llvm/MC/MCTargetOptions.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" +#include "llvm/Option/OptSpecifier.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/CodeGen.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/VersionTuple.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetOptions.h" -#include "llvm/Support/ScopedPrinter.h" +#include <algorithm> #include <atomic> +#include <cassert> +#include <cstddef> +#include <cstring> #include <memory> -#include <sys/stat.h> -#include <system_error> +#include <string> +#include <tuple> +#include <utility> +#include <vector> + using namespace clang; +using namespace driver; +using namespace options; +using namespace llvm::opt; //===----------------------------------------------------------------------===// // Initialization. //===----------------------------------------------------------------------===// CompilerInvocationBase::CompilerInvocationBase() - : LangOpts(new LangOptions()), TargetOpts(new TargetOptions()), - DiagnosticOpts(new DiagnosticOptions()), - HeaderSearchOpts(new HeaderSearchOptions()), - PreprocessorOpts(new PreprocessorOptions()) {} + : LangOpts(new LangOptions()), TargetOpts(new TargetOptions()), + DiagnosticOpts(new DiagnosticOptions()), + HeaderSearchOpts(new HeaderSearchOptions()), + PreprocessorOpts(new PreprocessorOptions()) {} CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &X) : LangOpts(new LangOptions(*X.getLangOpts())), @@ -66,18 +111,12 @@ CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &X) HeaderSearchOpts(new HeaderSearchOptions(X.getHeaderSearchOpts())), PreprocessorOpts(new PreprocessorOptions(X.getPreprocessorOpts())) {} -CompilerInvocationBase::~CompilerInvocationBase() {} +CompilerInvocationBase::~CompilerInvocationBase() = default; //===----------------------------------------------------------------------===// // Deserialization (from args) //===----------------------------------------------------------------------===// -using namespace clang::driver; -using namespace clang::driver::options; -using namespace llvm::opt; - -// - static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, DiagnosticsEngine &Diags) { unsigned DefaultOpt = 0; @@ -91,7 +130,7 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, if (A->getOption().matches(options::OPT_Ofast)) return 3; - assert (A->getOption().matches(options::OPT_O)); + assert(A->getOption().matches(options::OPT_O)); StringRef S(A->getValue()); if (S == "s" || S == "z" || S.empty()) @@ -125,7 +164,7 @@ static unsigned getOptimizationLevelSize(ArgList &Args) { static void addDiagnosticArgs(ArgList &Args, OptSpecifier Group, OptSpecifier GroupWithValue, std::vector<std::string> &Diagnostics) { - for (Arg *A : Args.filtered(Group)) { + for (auto *A : Args.filtered(Group)) { if (A->getOption().getKind() == Option::FlagClass) { // The argument is a pure flag (such as OPT_Wall or OPT_Wdeprecated). Add // its name (minus the "W" or "R" at the beginning) to the warning list. @@ -135,7 +174,7 @@ static void addDiagnosticArgs(ArgList &Args, OptSpecifier Group, Diagnostics.push_back(A->getOption().getName().drop_front(1).rtrim("=-")); } else { // Otherwise, add its value (for OPT_W_Joined and similar). - for (const char *Arg : A->getValues()) + for (const auto *Arg : A->getValues()) Diagnostics.emplace_back(Arg); } } @@ -157,7 +196,6 @@ static void getAllNoBuiltinFuncValues(ArgList &Args, static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { - using namespace options; bool Success = true; if (Arg *A = Args.getLastArg(OPT_analyzer_store)) { StringRef Name = A->getValue(); @@ -273,31 +311,31 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, StringRef checkerList = A->getValue(); SmallVector<StringRef, 4> checkers; checkerList.split(checkers, ","); - for (StringRef checker : checkers) + for (auto checker : checkers) Opts.CheckersControlList.emplace_back(checker, enable); } // Go through the analyzer configuration options. - for (const Arg *A : Args.filtered(OPT_analyzer_config)) { + for (const auto *A : Args.filtered(OPT_analyzer_config)) { A->claim(); // We can have a list of comma separated config names, e.g: // '-analyzer-config key1=val1,key2=val2' StringRef configList = A->getValue(); SmallVector<StringRef, 4> configVals; configList.split(configVals, ","); - for (unsigned i = 0, e = configVals.size(); i != e; ++i) { + for (const auto &configVal : configVals) { StringRef key, val; - std::tie(key, val) = configVals[i].split("="); + std::tie(key, val) = configVal.split("="); if (val.empty()) { Diags.Report(SourceLocation(), - diag::err_analyzer_config_no_value) << configVals[i]; + diag::err_analyzer_config_no_value) << configVal; Success = false; break; } if (val.find('=') != StringRef::npos) { Diags.Report(SourceLocation(), diag::err_analyzer_config_multiple_values) - << configVals[i]; + << configVal; Success = false; break; } @@ -305,6 +343,14 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } } + llvm::raw_string_ostream os(Opts.FullCompilerInvocation); + for (unsigned i = 0; i < Args.getNumInputArgStrings(); ++i) { + if (i != 0) + os << " "; + os << Args.getArgString(i); + } + os.flush(); + return Success; } @@ -330,18 +376,26 @@ static StringRef getCodeModel(ArgList &Args, DiagnosticsEngine &Diags) { return "default"; } -static StringRef getRelocModel(ArgList &Args, DiagnosticsEngine &Diags) { +static llvm::Reloc::Model getRelocModel(ArgList &Args, + DiagnosticsEngine &Diags) { if (Arg *A = Args.getLastArg(OPT_mrelocation_model)) { StringRef Value = A->getValue(); - if (Value == "static" || Value == "pic" || Value == "ropi" || - Value == "rwpi" || Value == "ropi-rwpi" || Value == "dynamic-no-pic") - return Value; + auto RM = llvm::StringSwitch<llvm::Optional<llvm::Reloc::Model>>(Value) + .Case("static", llvm::Reloc::Static) + .Case("pic", llvm::Reloc::PIC_) + .Case("ropi", llvm::Reloc::ROPI) + .Case("rwpi", llvm::Reloc::RWPI) + .Case("ropi-rwpi", llvm::Reloc::ROPI_RWPI) + .Case("dynamic-no-pic", llvm::Reloc::DynamicNoPIC) + .Default(None); + if (RM.hasValue()) + return *RM; Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Value; } - return "pic"; + return llvm::Reloc::PIC_; } -/// \brief Create a new Regex instance out of the string value in \p RpassArg. +/// Create a new Regex instance out of the string value in \p RpassArg. /// It returns a pointer to the newly generated Regex instance. static std::shared_ptr<llvm::Regex> GenerateOptimizationRemarkRegex(DiagnosticsEngine &Diags, ArgList &Args, @@ -392,6 +446,25 @@ static void parseSanitizerKinds(StringRef FlagName, } } +static void parseXRayInstrumentationBundle(StringRef FlagName, StringRef Bundle, + ArgList &Args, DiagnosticsEngine &D, + XRayInstrSet &S) { + llvm::SmallVector<StringRef, 2> BundleParts; + llvm::SplitString(Bundle, BundleParts, ","); + for (const auto B : BundleParts) { + auto Mask = parseXRayInstrValue(B); + if (Mask == XRayInstrKind::None) + if (B != "none") + D.Report(diag::err_drv_invalid_value) << FlagName << Bundle; + else + S.Mask = Mask; + else if (Mask == XRayInstrKind::All) + S.Mask = Mask; + else + S.set(Mask, true); + } +} + // Set the profile kind for fprofile-instrument. static void setPGOInstrumentor(CodeGenOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { @@ -409,8 +482,7 @@ static void setPGOInstrumentor(CodeGenOptions &Opts, ArgList &Args, << S; return; } - CodeGenOptions::ProfileInstrKind Instrumentor = - static_cast<CodeGenOptions::ProfileInstrKind>(I); + auto Instrumentor = static_cast<CodeGenOptions::ProfileInstrKind>(I); Opts.setProfileInstr(Instrumentor); } @@ -434,8 +506,8 @@ static void setPGOUseInstrumentor(CodeGenOptions &Opts, static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, DiagnosticsEngine &Diags, - const TargetOptions &TargetOpts) { - using namespace options; + const TargetOptions &TargetOpts, + const FrontendOptions &FrontendOpts) { bool Success = true; llvm::Triple Triple = llvm::Triple(TargetOpts.Triple); @@ -474,7 +546,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.ExperimentalNewPassManager = Args.hasFlag( OPT_fexperimental_new_pass_manager, OPT_fno_experimental_new_pass_manager, - /* Default */ false); + /* Default */ ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER); Opts.DebugPassManager = Args.hasFlag(OPT_fdebug_pass_manager, OPT_fno_debug_pass_manager, @@ -529,6 +601,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DebugTypeExtRefs = Args.hasArg(OPT_dwarf_ext_refs); Opts.DebugExplicitImport = Args.hasArg(OPT_dwarf_explicit_import); Opts.DebugFwdTemplateParams = Args.hasArg(OPT_debug_forward_template_params); + Opts.EmbedSource = Args.hasArg(OPT_gembed_source); for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) Opts.DebugPrefixMap.insert(StringRef(Arg).split('=')); @@ -552,7 +625,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Args.hasFlag(OPT_ffine_grained_bitfield_accesses, OPT_fno_fine_grained_bitfield_accesses, false); Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags); - Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants); + Opts.MergeAllConstants = Args.hasArg(OPT_fmerge_all_constants); Opts.NoCommon = Args.hasArg(OPT_fno_common); Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float); Opts.OptimizeSize = getOptimizationLevelSize(Args); @@ -580,33 +653,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, if (!Opts.ProfileInstrumentUsePath.empty()) setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath); - if (Arg *A = Args.getLastArg(OPT_fclang_abi_compat_EQ)) { - Opts.setClangABICompat(CodeGenOptions::ClangABI::Latest); - - StringRef Ver = A->getValue(); - std::pair<StringRef, StringRef> VerParts = Ver.split('.'); - unsigned Major, Minor = 0; - - // Check the version number is valid: either 3.x (0 <= x <= 9) or - // y or y.0 (4 <= y <= current version). - if (!VerParts.first.startswith("0") && - !VerParts.first.getAsInteger(10, Major) && - 3 <= Major && Major <= CLANG_VERSION_MAJOR && - (Major == 3 ? VerParts.second.size() == 1 && - !VerParts.second.getAsInteger(10, Minor) - : VerParts.first.size() == Ver.size() || - VerParts.second == "0")) { - // Got a valid version number. - if (Major == 3 && Minor <= 8) - Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver3_8); - else if (Major <= 4) - Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver4); - } else if (Ver != "latest") { - Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << A->getValue(); - } - } - Opts.CoverageMapping = Args.hasFlag(OPT_fcoverage_mapping, OPT_fno_coverage_mapping, false); Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping); @@ -615,6 +661,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new); Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); + Opts.RegisterGlobalDtorsWithAtExit = + Args.hasArg(OPT_fregister_global_dtors_with_atexit); Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); Opts.CodeModel = getCodeModel(Args, Diags); Opts.DebugPass = Args.getLastArgValue(OPT_mdebug_pass); @@ -623,6 +671,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DisableFree = Args.hasArg(OPT_disable_free); Opts.DiscardValueNames = Args.hasArg(OPT_discard_value_names); Opts.DisableTailCalls = Args.hasArg(OPT_mdisable_tail_calls); + Opts.NoEscapingBlockTailCalls = + Args.hasArg(OPT_fno_escaping_block_tail_calls); Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi); Opts.LessPreciseFPMAD = Args.hasArg(OPT_cl_mad_enable) || Args.hasArg(OPT_cl_unsafe_math_optimizations) || @@ -640,14 +690,20 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Args.hasArg(OPT_cl_unsafe_math_optimizations) || Args.hasArg(OPT_cl_fast_relaxed_math)); Opts.Reassociate = Args.hasArg(OPT_mreassociate); - Opts.FlushDenorm = Args.hasArg(OPT_cl_denorms_are_zero); + Opts.FlushDenorm = Args.hasArg(OPT_cl_denorms_are_zero) || + (Args.hasArg(OPT_fcuda_is_device) && + Args.hasArg(OPT_fcuda_flush_denormals_to_zero)); Opts.CorrectlyRoundedDivSqrt = Args.hasArg(OPT_cl_fp32_correctly_rounded_divide_sqrt); + Opts.UniformWGSize = + Args.hasArg(OPT_cl_uniform_work_group_size); Opts.Reciprocals = Args.getAllArgValues(OPT_mrecip_EQ); Opts.ReciprocalMath = Args.hasArg(OPT_freciprocal_math); Opts.NoTrappingMath = Args.hasArg(OPT_fno_trapping_math); + Opts.StrictFloatCastOverflow = + !Args.hasArg(OPT_fno_strict_float_cast_overflow); + Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss); - Opts.BackendOptions = Args.getAllArgValues(OPT_backend_option); Opts.NumRegisterParameters = getLastArgIntValue(Args, OPT_mregparm, 0, Diags); Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack); Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings); @@ -665,6 +721,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.StrictEnums = Args.hasArg(OPT_fstrict_enums); Opts.StrictReturn = !Args.hasArg(OPT_fno_strict_return); Opts.StrictVTablePointers = Args.hasArg(OPT_fstrict_vtable_pointers); + Opts.ForceEmitVTables = Args.hasArg(OPT_fforce_emit_vtables); Opts.UnsafeFPMath = Args.hasArg(OPT_menable_unsafe_fp_math) || Args.hasArg(OPT_cl_unsafe_math_optimizations) || Args.hasArg(OPT_cl_fast_relaxed_math); @@ -682,6 +739,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, OPT_fno_function_sections, false); Opts.DataSections = Args.hasFlag(OPT_fdata_sections, OPT_fno_data_sections, false); + Opts.StackSizeSection = + Args.hasFlag(OPT_fstack_size_section, OPT_fno_stack_size_section, false); Opts.UniqueSectionNames = Args.hasFlag(OPT_funique_section_names, OPT_fno_unique_section_names, true); @@ -689,14 +748,16 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.NoUseJumpTables = Args.hasArg(OPT_fno_jump_tables); + Opts.NullPointerIsValid = Args.hasArg(OPT_fno_delete_null_pointer_checks); + Opts.ProfileSampleAccurate = Args.hasArg(OPT_fprofile_sample_accurate); Opts.PrepareForLTO = Args.hasArg(OPT_flto, OPT_flto_EQ); - Opts.EmitSummaryIndex = false; + Opts.PrepareForThinLTO = false; if (Arg *A = Args.getLastArg(OPT_flto_EQ)) { StringRef S = A->getValue(); if (S == "thin") - Opts.EmitSummaryIndex = true; + Opts.PrepareForThinLTO = true; else if (S != "full") Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << S; } @@ -707,6 +768,12 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, << A->getAsString(Args) << "-x ir"; Opts.ThinLTOIndexFile = Args.getLastArgValue(OPT_fthinlto_index_EQ); } + if (Arg *A = Args.getLastArg(OPT_save_temps_EQ)) + Opts.SaveTempsFilePrefix = + llvm::StringSwitch<std::string>(A->getValue()) + .Case("obj", FrontendOpts.OutputFile) + .Default(llvm::sys::path::filename(FrontendOpts.OutputFile).str()); + Opts.ThinLinkBitcodeFile = Args.getLastArgValue(OPT_fthin_link_bitcode_EQ); Opts.MSVolatile = Args.hasArg(OPT_fms_volatile); @@ -719,6 +786,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name); Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier); + Opts.ControlFlowGuard = Args.hasArg(OPT_cfguard); + Opts.DisableGCov = Args.hasArg(OPT_test_coverage); Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data); Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes); @@ -741,7 +810,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, } } } - // Handle -fembed-bitcode option. + // Handle -fembed-bitcode option. if (Arg *A = Args.getLastArg(OPT_fembed_bitcode_EQ)) { StringRef Name = A->getValue(); unsigned Model = llvm::StringSwitch<unsigned>(Name) @@ -787,15 +856,44 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Args.hasArg(OPT_finstrument_functions_after_inlining); Opts.InstrumentFunctionEntryBare = Args.hasArg(OPT_finstrument_function_entry_bare); - Opts.XRayInstrumentFunctions = Args.hasArg(OPT_fxray_instrument); + + Opts.XRayInstrumentFunctions = + Args.hasArg(OPT_fxray_instrument); Opts.XRayAlwaysEmitCustomEvents = Args.hasArg(OPT_fxray_always_emit_customevents); + Opts.XRayAlwaysEmitTypedEvents = + Args.hasArg(OPT_fxray_always_emit_typedevents); Opts.XRayInstructionThreshold = getLastArgIntValue(Args, OPT_fxray_instruction_threshold_EQ, 200, Diags); + + auto XRayInstrBundles = + Args.getAllArgValues(OPT_fxray_instrumentation_bundle); + if (XRayInstrBundles.empty()) + Opts.XRayInstrumentationBundle.Mask = XRayInstrKind::All; + else + for (const auto &A : XRayInstrBundles) + parseXRayInstrumentationBundle("-fxray-instrumentation-bundle=", A, Args, + Diags, Opts.XRayInstrumentationBundle); + Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); Opts.CallFEntry = Args.hasArg(OPT_mfentry); Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info); + if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) { + StringRef Name = A->getValue(); + if (Name == "full") { + Opts.CFProtectionReturn = 1; + Opts.CFProtectionBranch = 1; + } else if (Name == "return") + Opts.CFProtectionReturn = 1; + else if (Name == "branch") + Opts.CFProtectionBranch = 1; + else if (Name != "none") { + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; + Success = false; + } + } + if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections, OPT_compress_debug_sections_EQ)) { if (A->getOption().getID() == OPT_compress_debug_sections) { @@ -813,7 +911,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations); Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir); - for (auto A : Args.filtered(OPT_mlink_bitcode_file, OPT_mlink_cuda_bitcode)) { + for (auto *A : + Args.filtered(OPT_mlink_bitcode_file, OPT_mlink_cuda_bitcode)) { CodeGenOptions::BitcodeFileToLink F; F.Filename = A->getValue(); if (A->getOption().matches(OPT_mlink_cuda_bitcode)) { @@ -855,6 +954,13 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.SanitizeCfiICallGeneralizePointers = Args.hasArg(OPT_fsanitize_cfi_icall_generalize_pointers); Opts.SanitizeStats = Args.hasArg(OPT_fsanitize_stats); + if (Arg *A = Args.getLastArg( + OPT_fsanitize_address_poison_class_member_array_new_cookie, + OPT_fno_sanitize_address_poison_class_member_array_new_cookie)) { + Opts.SanitizeAddressPoisonClassMemberArrayNewCookie = + A->getOption().getID() == + OPT_fsanitize_address_poison_class_member_array_new_cookie; + } if (Arg *A = Args.getLastArg(OPT_fsanitize_address_use_after_scope, OPT_fno_sanitize_address_use_after_scope)) { Opts.SanitizeAddressUseAfterScope = @@ -881,6 +987,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.StackProbeSize = StackProbeSize; } + Opts.NoStackArgProbe = Args.hasArg(OPT_mno_stack_arg_probe); + if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) { StringRef Name = A->getValue(); unsigned Method = llvm::StringSwitch<unsigned>(Name) @@ -897,8 +1005,12 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, } } - Opts.EmulatedTLS = - Args.hasFlag(OPT_femulated_tls, OPT_fno_emulated_tls, false); + if (Args.getLastArg(OPT_femulated_tls) || + Args.getLastArg(OPT_fno_emulated_tls)) { + Opts.ExplicitEmulatedTLS = true; + Opts.EmulatedTLS = + Args.hasFlag(OPT_femulated_tls, OPT_fno_emulated_tls, false); + } if (Arg *A = Args.getLastArg(OPT_ftlsmodel_EQ)) { StringRef Name = A->getValue(); @@ -969,7 +1081,9 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, bool UsingProfile = UsingSampleProfile || (Opts.getProfileUse() != CodeGenOptions::ProfileNone); - if (Opts.DiagnosticsWithHotness && !UsingProfile) + if (Opts.DiagnosticsWithHotness && !UsingProfile && + // An IR file will contain PGO as metadata + IK.getLanguage() != InputKind::LLVM_IR) Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo) << "-fdiagnostics-show-hotness"; @@ -1001,20 +1115,23 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Args.getAllArgValues(OPT_fsanitize_trap_EQ), Diags, Opts.SanitizeTrap); - Opts.CudaGpuBinaryFileNames = - Args.getAllArgValues(OPT_fcuda_include_gpubinary); + Opts.CudaGpuBinaryFileName = + Args.getLastArgValue(OPT_fcuda_include_gpubinary); Opts.Backchain = Args.hasArg(OPT_mbackchain); Opts.EmitCheckPathComponentsToStrip = getLastArgIntValue( Args, OPT_fsanitize_undefined_strip_path_components_EQ, 0, Diags); + Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true); + + Opts.Addrsig = Args.hasArg(OPT_faddrsig); + return Success; } static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, ArgList &Args) { - using namespace options; Opts.OutputFile = Args.getLastArgValue(OPT_dependency_file); Opts.Targets = Args.getAllArgValues(OPT_MT); Opts.IncludeSystemHeaders = Args.hasArg(OPT_sys_header_deps); @@ -1023,7 +1140,17 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, Opts.ShowHeaderIncludes = Args.hasArg(OPT_H); Opts.HeaderIncludeOutputFile = Args.getLastArgValue(OPT_header_include_file); Opts.AddMissingHeaderDeps = Args.hasArg(OPT_MG); - Opts.PrintShowIncludes = Args.hasArg(OPT_show_includes); + if (Args.hasArg(OPT_show_includes)) { + // Writing both /showIncludes and preprocessor output to stdout + // would produce interleaved output, so use stderr for /showIncludes. + // This behaves the same as cl.exe, when /E, /EP or /P are passed. + if (Args.hasArg(options::OPT_E) || Args.hasArg(options::OPT_P)) + Opts.ShowIncludesDest = ShowIncludesDestination::Stderr; + else + Opts.ShowIncludesDest = ShowIncludesDestination::Stdout; + } else { + Opts.ShowIncludesDest = ShowIncludesDestination::None; + } Opts.DOTOutputFile = Args.getLastArgValue(OPT_dependency_dot); Opts.ModuleDependencyOutputDir = Args.getLastArgValue(OPT_module_dependency_dir); @@ -1034,7 +1161,7 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, // we let make / ninja to know about this implicit dependency. Opts.ExtraDeps = Args.getAllArgValues(OPT_fdepfile_entry); // Only the -fmodule-file=<file> form. - for (const Arg *A : Args.filtered(OPT_fmodule_file)) { + for (const auto *A : Args.filtered(OPT_fmodule_file)) { StringRef Val = A->getValue(); if (Val.find('=') == StringRef::npos) Opts.ExtraDeps.push_back(Val); @@ -1051,7 +1178,7 @@ static bool parseShowColorsArgs(const ArgList &Args, bool DefaultColor) { Colors_Off, Colors_Auto } ShowColors = DefaultColor ? Colors_Auto : Colors_Off; - for (Arg *A : Args) { + for (auto *A : Args) { const Option &O = A->getOption(); if (O.matches(options::OPT_fcolor_diagnostics) || O.matches(options::OPT_fdiagnostics_color)) { @@ -1097,7 +1224,6 @@ static bool checkVerifyPrefixes(const std::vector<std::string> &VerifyPrefixes, bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, DiagnosticsEngine *Diags, bool DefaultDiagColor, bool DefaultShowOpt) { - using namespace options; bool Success = true; Opts.DiagnosticLogFile = Args.getLastArgValue(OPT_diagnostic_log_file); @@ -1192,7 +1318,7 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Success = false; } else - std::sort(Opts.VerifyPrefixes.begin(), Opts.VerifyPrefixes.end()); + llvm::sort(Opts.VerifyPrefixes.begin(), Opts.VerifyPrefixes.end()); DiagnosticLevelMask DiagMask = DiagnosticLevelMask::None; Success &= parseDiagnosticLevelMask("-verify-ignore-unexpected=", Args.getAllArgValues(OPT_verify_ignore_unexpected_EQ), @@ -1264,7 +1390,6 @@ static bool parseTestModuleFileExtensionArg(StringRef Arg, static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags, bool &IsHeaderFile) { - using namespace options; Opts.ProgramAction = frontend::ParseSyntaxOnly; if (const Arg *A = Args.getLastArg(OPT_Action_Group)) { switch (A->getOption().getID()) { @@ -1280,6 +1405,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ProgramAction = frontend::ASTPrint; break; case OPT_ast_view: Opts.ProgramAction = frontend::ASTView; break; + case OPT_compiler_options_dump: + Opts.ProgramAction = frontend::DumpCompilerOptions; break; case OPT_dump_raw_tokens: Opts.ProgramAction = frontend::DumpRawTokens; break; case OPT_dump_tokens: @@ -1325,6 +1452,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ProgramAction = frontend::PrintPreamble; break; case OPT_E: Opts.ProgramAction = frontend::PrintPreprocessedInput; break; + case OPT_templight_dump: + Opts.ProgramAction = frontend::TemplightDump; break; case OPT_rewrite_macros: Opts.ProgramAction = frontend::RewriteMacros; break; case OPT_rewrite_objc: @@ -1346,7 +1475,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ActionName = A->getValue(); } Opts.AddPluginActions = Args.getAllArgValues(OPT_add_plugin); - for (const Arg *AA : Args.filtered(OPT_plugin_arg)) + for (const auto *AA : Args.filtered(OPT_plugin_arg)) Opts.PluginArgs[AA->getValue(0)].emplace_back(AA->getValue(1)); for (const std::string &Arg : @@ -1399,7 +1528,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.GenerateGlobalModuleIndex = Opts.UseGlobalModuleIndex; Opts.ModuleMapFiles = Args.getAllArgValues(OPT_fmodule_map_file); // Only the -fmodule-file=<file> form. - for (const Arg *A : Args.filtered(OPT_fmodule_file)) { + for (const auto *A : Args.filtered(OPT_fmodule_file)) { StringRef Val = A->getValue(); if (Val.find('=') == StringRef::npos) Opts.ModuleFiles.push_back(Val); @@ -1418,12 +1547,13 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, = !Args.hasArg(OPT_no_code_completion_ns_level_decls); Opts.CodeCompleteOpts.IncludeBriefComments = Args.hasArg(OPT_code_completion_brief_comments); + Opts.CodeCompleteOpts.IncludeFixIts + = Args.hasArg(OPT_code_completion_with_fixits); Opts.OverrideRecordLayoutsFile = Args.getLastArgValue(OPT_foverride_record_layout_EQ); Opts.AuxTriple = llvm::Triple::normalize(Args.getLastArgValue(OPT_aux_triple)); - Opts.FindPchSource = Args.getLastArgValue(OPT_find_pch_source_EQ); Opts.StatsFile = Args.getLastArgValue(OPT_stats_file); if (const Arg *A = Args.getLastArg(OPT_arcmt_check, @@ -1504,6 +1634,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, .Case("c", InputKind::C) .Case("cl", InputKind::OpenCL) .Case("cuda", InputKind::CUDA) + .Case("hip", InputKind::HIP) .Case("c++", InputKind::CXX) .Case("objective-c", InputKind::ObjC) .Case("objective-c++", InputKind::ObjCXX) @@ -1587,7 +1718,6 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0, static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, const std::string &WorkingDir) { - using namespace options; Opts.Sysroot = Args.getLastArgValue(OPT_isysroot, "/"); Opts.Verbose = Args.hasArg(OPT_v); Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc); @@ -1610,12 +1740,12 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, Opts.ModuleUserBuildPath = Args.getLastArgValue(OPT_fmodules_user_build_path); // Only the -fmodule-file=<name>=<file> form. - for (const Arg *A : Args.filtered(OPT_fmodule_file)) { + for (const auto *A : Args.filtered(OPT_fmodule_file)) { StringRef Val = A->getValue(); if (Val.find('=') != StringRef::npos) Opts.PrebuiltModuleFiles.insert(Val.split('=')); } - for (const Arg *A : Args.filtered(OPT_fprebuilt_module_path)) + for (const auto *A : Args.filtered(OPT_fprebuilt_module_path)) Opts.AddPrebuiltModulePath(A->getValue()); Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash); Opts.ModulesHashContent = Args.hasArg(OPT_fmodules_hash_content); @@ -1636,7 +1766,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, if (const Arg *A = Args.getLastArg(OPT_fmodule_format_EQ)) Opts.ModuleFormat = A->getValue(); - for (const Arg *A : Args.filtered(OPT_fmodules_ignore_macro)) { + for (const auto *A : Args.filtered(OPT_fmodules_ignore_macro)) { StringRef MacroDef = A->getValue(); Opts.ModulesIgnoreMacros.insert( llvm::CachedHashString(MacroDef.split('=').first)); @@ -1646,7 +1776,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, bool IsIndexHeaderMap = false; bool IsSysrootSpecified = Args.hasArg(OPT__sysroot_EQ) || Args.hasArg(OPT_isysroot); - for (const Arg *A : Args.filtered(OPT_I, OPT_F, OPT_index_header_map)) { + for (const auto *A : Args.filtered(OPT_I, OPT_F, OPT_index_header_map)) { if (A->getOption().matches(OPT_index_header_map)) { // -index-header-map applies to the next -I or -F. IsIndexHeaderMap = true; @@ -1673,7 +1803,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, // Add -iprefix/-iwithprefix/-iwithprefixbefore options. StringRef Prefix = ""; // FIXME: This isn't the correct default prefix. - for (const Arg *A : + for (const auto *A : Args.filtered(OPT_iprefix, OPT_iwithprefix, OPT_iwithprefixbefore)) { if (A->getOption().matches(OPT_iprefix)) Prefix = A->getValue(); @@ -1683,31 +1813,31 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, Opts.AddPath(Prefix.str() + A->getValue(), frontend::Angled, false, true); } - for (const Arg *A : Args.filtered(OPT_idirafter)) + for (const auto *A : Args.filtered(OPT_idirafter)) Opts.AddPath(A->getValue(), frontend::After, false, true); - for (const Arg *A : Args.filtered(OPT_iquote)) + for (const auto *A : Args.filtered(OPT_iquote)) Opts.AddPath(A->getValue(), frontend::Quoted, false, true); - for (const Arg *A : Args.filtered(OPT_isystem, OPT_iwithsysroot)) + for (const auto *A : Args.filtered(OPT_isystem, OPT_iwithsysroot)) Opts.AddPath(A->getValue(), frontend::System, false, !A->getOption().matches(OPT_iwithsysroot)); - for (const Arg *A : Args.filtered(OPT_iframework)) + for (const auto *A : Args.filtered(OPT_iframework)) Opts.AddPath(A->getValue(), frontend::System, true, true); - for (const Arg *A : Args.filtered(OPT_iframeworkwithsysroot)) + for (const auto *A : Args.filtered(OPT_iframeworkwithsysroot)) Opts.AddPath(A->getValue(), frontend::System, /*IsFramework=*/true, /*IgnoreSysRoot=*/false); // Add the paths for the various language specific isystem flags. - for (const Arg *A : Args.filtered(OPT_c_isystem)) + for (const auto *A : Args.filtered(OPT_c_isystem)) Opts.AddPath(A->getValue(), frontend::CSystem, false, true); - for (const Arg *A : Args.filtered(OPT_cxx_isystem)) + for (const auto *A : Args.filtered(OPT_cxx_isystem)) Opts.AddPath(A->getValue(), frontend::CXXSystem, false, true); - for (const Arg *A : Args.filtered(OPT_objc_isystem)) + for (const auto *A : Args.filtered(OPT_objc_isystem)) Opts.AddPath(A->getValue(), frontend::ObjCSystem, false,true); - for (const Arg *A : Args.filtered(OPT_objcxx_isystem)) + for (const auto *A : Args.filtered(OPT_objcxx_isystem)) Opts.AddPath(A->getValue(), frontend::ObjCXXSystem, false, true); // Add the internal paths from a driver that detects standard include paths. - for (const Arg *A : + for (const auto *A : Args.filtered(OPT_internal_isystem, OPT_internal_externc_isystem)) { frontend::IncludeDirGroup Group = frontend::System; if (A->getOption().matches(OPT_internal_externc_isystem)) @@ -1716,12 +1846,12 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, } // Add the path prefixes which are implicitly treated as being system headers. - for (const Arg *A : + for (const auto *A : Args.filtered(OPT_system_header_prefix, OPT_no_system_header_prefix)) Opts.AddSystemHeaderPrefix( A->getValue(), A->getOption().matches(OPT_system_header_prefix)); - for (const Arg *A : Args.filtered(OPT_ivfsoverlay)) + for (const auto *A : Args.filtered(OPT_ivfsoverlay)) Opts.AddVFSOverlayFile(A->getValue()); } @@ -1756,22 +1886,37 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, break; case InputKind::Asm: case InputKind::C: +#if defined(CLANG_DEFAULT_STD_C) + LangStd = CLANG_DEFAULT_STD_C; +#else // The PS4 uses C99 as the default C standard. if (T.isPS4()) LangStd = LangStandard::lang_gnu99; else LangStd = LangStandard::lang_gnu11; +#endif break; case InputKind::ObjC: +#if defined(CLANG_DEFAULT_STD_C) + LangStd = CLANG_DEFAULT_STD_C; +#else LangStd = LangStandard::lang_gnu11; +#endif break; case InputKind::CXX: case InputKind::ObjCXX: +#if defined(CLANG_DEFAULT_STD_CXX) + LangStd = CLANG_DEFAULT_STD_CXX; +#else LangStd = LangStandard::lang_gnucxx14; +#endif break; case InputKind::RenderScript: LangStd = LangStandard::lang_c99; break; + case InputKind::HIP: + LangStd = LangStandard::lang_hip; + break; } } @@ -1801,6 +1946,8 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.OpenCLVersion = 120; else if (LangStd == LangStandard::lang_opencl20) Opts.OpenCLVersion = 200; + else if (LangStd == LangStandard::lang_openclcpp) + Opts.OpenCLCPlusPlusVersion = 100; // OpenCL has some additional defaults. if (Opts.OpenCL) { @@ -1810,13 +1957,15 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.setDefaultFPContractMode(LangOptions::FPC_On); Opts.NativeHalfType = 1; Opts.NativeHalfArgsAndReturns = 1; + Opts.OpenCLCPlusPlus = Opts.CPlusPlus; // Include default header file for OpenCL. if (Opts.IncludeDefaultHeader) { PPOpts.Includes.push_back("opencl-c.h"); } } - Opts.CUDA = IK.getLanguage() == InputKind::CUDA; + Opts.HIP = IK.getLanguage() == InputKind::HIP; + Opts.CUDA = IK.getLanguage() == InputKind::CUDA || Opts.HIP; if (Opts.CUDA) // Set default FP_CONTRACT to FAST. Opts.setDefaultFPContractMode(LangOptions::FPC_Fast); @@ -1887,6 +2036,10 @@ static bool IsInputCompatibleWithStandard(InputKind IK, return S.getLanguage() == InputKind::CUDA || S.getLanguage() == InputKind::CXX; + case InputKind::HIP: + return S.getLanguage() == InputKind::CXX || + S.getLanguage() == InputKind::HIP; + case InputKind::Asm: // Accept (and ignore) all -std= values. // FIXME: The -std= value is not ignored; it affects the tokenization @@ -1914,6 +2067,8 @@ static const StringRef GetInputKindName(InputKind IK) { return "CUDA"; case InputKind::RenderScript: return "RenderScript"; + case InputKind::HIP: + return "HIP"; case InputKind::Asm: return "Asm"; @@ -1977,6 +2132,12 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, } } + if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) { + StringRef Name = A->getValue(); + if (Name == "full" || Name == "branch") { + Opts.CFProtectionBranch = 1; + } + } // -cl-std only applies for OpenCL language standards. // Override the -std option in this case. if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) { @@ -1986,6 +2147,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, .Cases("cl1.1", "CL1.1", LangStandard::lang_opencl11) .Cases("cl1.2", "CL1.2", LangStandard::lang_opencl12) .Cases("cl2.0", "CL2.0", LangStandard::lang_opencl20) + .Case("c++", LangStandard::lang_openclcpp) .Default(LangStandard::lang_unspecified); if (OpenCLLangStd == LangStandard::lang_unspecified) { @@ -2006,11 +2168,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // this option was added for compatibility with OpenCL 1.0. if (Args.getLastArg(OPT_cl_strict_aliasing) && Opts.OpenCLVersion > 100) { - std::string VerSpec = llvm::to_string(Opts.OpenCLVersion / 100) + - std::string(".") + - llvm::to_string((Opts.OpenCLVersion % 100) / 10); Diags.Report(diag::warn_option_invalid_ocl_version) - << VerSpec << Args.getLastArg(OPT_cl_strict_aliasing)->getAsString(Args); + << Opts.getOpenCLVersionTuple().getAsString() + << Args.getLastArg(OPT_cl_strict_aliasing)->getAsString(Args); } // We abuse '-f[no-]gnu-keywords' to force overriding all GNU-extension @@ -2021,6 +2181,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.GNUKeywords = Args.hasFlag(OPT_fgnu_keywords, OPT_fno_gnu_keywords, Opts.GNUKeywords); + Opts.Digraphs = Args.hasFlag(OPT_fdigraphs, OPT_fno_digraphs, Opts.Digraphs); + if (Args.hasArg(OPT_fno_operator_names)) Opts.CXXOperatorNames = 0; @@ -2033,12 +2195,11 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Args.hasArg(OPT_fno_cuda_host_device_constexpr)) Opts.CUDAHostDeviceConstexpr = 0; - if (Opts.CUDAIsDevice && Args.hasArg(OPT_fcuda_flush_denormals_to_zero)) - Opts.CUDADeviceFlushDenormalsToZero = 1; - if (Opts.CUDAIsDevice && Args.hasArg(OPT_fcuda_approx_transcendentals)) Opts.CUDADeviceApproxTranscendentals = 1; + Opts.CUDARelocatableDeviceCode = Args.hasArg(OPT_fcuda_rdc); + if (Opts.ObjC1) { if (Arg *arg = Args.getLastArg(OPT_fobjc_runtime_EQ)) { StringRef value = arg->getValue(); @@ -2179,12 +2340,27 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.ObjCExceptions = Args.hasArg(OPT_fobjc_exceptions); Opts.CXXExceptions = Args.hasArg(OPT_fcxx_exceptions); + // -ffixed-point + Opts.FixedPoint = + Args.hasFlag(OPT_ffixed_point, OPT_fno_fixed_point, /*Default=*/false) && + !Opts.CPlusPlus; + Opts.PaddingOnUnsignedFixedPoint = + Args.hasFlag(OPT_fpadding_on_unsigned_fixed_point, + OPT_fno_padding_on_unsigned_fixed_point, + /*Default=*/false) && + Opts.FixedPoint; + // Handle exception personalities Arg *A = Args.getLastArg(options::OPT_fsjlj_exceptions, options::OPT_fseh_exceptions, options::OPT_fdwarf_exceptions); if (A) { const Option &Opt = A->getOption(); + llvm::Triple T(TargetOpts.Triple); + if (T.isWindowsMSVCEnvironment()) + Diags.Report(diag::err_fe_invalid_exception_model) + << Opt.getName() << T.str(); + Opts.SjLjExceptions = Opt.matches(options::OPT_fsjlj_exceptions); Opts.SEHExceptions = Opt.matches(options::OPT_fseh_exceptions); Opts.DWARFExceptions = Opt.matches(options::OPT_fdwarf_exceptions); @@ -2196,7 +2372,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.RTTI = Opts.CPlusPlus && !Args.hasArg(OPT_fno_rtti); Opts.RTTIData = Opts.RTTI && !Args.hasArg(OPT_fno_rtti_data); Opts.Blocks = Args.hasArg(OPT_fblocks) || (Opts.OpenCL - && Opts.OpenCLVersion >= 200); + && Opts.OpenCLVersion == 200); Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional); Opts.CoroutinesTS = Args.hasArg(OPT_fcoroutines_ts); @@ -2221,6 +2397,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.ImplicitModules = !Args.hasArg(OPT_fno_implicit_modules); Opts.CharIsSigned = Opts.OpenCL || !Args.hasArg(OPT_fno_signed_char); Opts.WChar = Opts.CPlusPlus && !Args.hasArg(OPT_fno_wchar); + Opts.Char8 = Args.hasArg(OPT_fchar8__t); if (const Arg *A = Args.getLastArg(OPT_fwchar_type_EQ)) { Opts.WCharSize = llvm::StringSwitch<unsigned>(A->getValue()) .Case("char", 1) @@ -2299,10 +2476,11 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.DebuggerCastResultToId = Args.hasArg(OPT_fdebugger_cast_result_to_id); Opts.DebuggerObjCLiteral = Args.hasArg(OPT_fdebugger_objc_literal); Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack); - Opts.CurrentModule = Args.getLastArgValue(OPT_fmodule_name_EQ); + Opts.ModuleName = Args.getLastArgValue(OPT_fmodule_name_EQ); + Opts.CurrentModule = Opts.ModuleName; Opts.AppExt = Args.hasArg(OPT_fapplication_extension); Opts.ModuleFeatures = Args.getAllArgValues(OPT_fmodule_feature); - std::sort(Opts.ModuleFeatures.begin(), Opts.ModuleFeatures.end()); + llvm::sort(Opts.ModuleFeatures.begin(), Opts.ModuleFeatures.end()); Opts.NativeHalfType |= Args.hasArg(OPT_fnative_half_type); Opts.NativeHalfArgsAndReturns |= Args.hasArg(OPT_fnative_half_arguments_and_returns); // Enable HalfArgsAndReturns if present in Args or if NativeHalfArgsAndReturns @@ -2410,20 +2588,23 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // Check if -fopenmp is specified. Opts.OpenMP = Args.hasArg(options::OPT_fopenmp) ? 1 : 0; // Check if -fopenmp-simd is specified. - Opts.OpenMPSimd = !Opts.OpenMP && Args.hasFlag(options::OPT_fopenmp_simd, - options::OPT_fno_openmp_simd, - /*Default=*/false); + bool IsSimdSpecified = + Args.hasFlag(options::OPT_fopenmp_simd, options::OPT_fno_openmp_simd, + /*Default=*/false); + Opts.OpenMPSimd = !Opts.OpenMP && IsSimdSpecified; Opts.OpenMPUseTLS = Opts.OpenMP && !Args.hasArg(options::OPT_fnoopenmp_use_tls); Opts.OpenMPIsDevice = Opts.OpenMP && Args.hasArg(options::OPT_fopenmp_is_device); + bool IsTargetSpecified = + Opts.OpenMPIsDevice || Args.hasArg(options::OPT_fopenmp_targets_EQ); if (Opts.OpenMP || Opts.OpenMPSimd) { - if (int Version = - getLastArgIntValue(Args, OPT_fopenmp_version_EQ, - Opts.OpenMPSimd ? 45 : Opts.OpenMP, Diags)) + if (int Version = getLastArgIntValue( + Args, OPT_fopenmp_version_EQ, + (IsSimdSpecified || IsTargetSpecified) ? 45 : Opts.OpenMP, Diags)) Opts.OpenMP = Version; - else if (Opts.OpenMPSimd) + else if (IsSimdSpecified || IsTargetSpecified) Opts.OpenMP = 45; // Provide diagnostic when a given target is not expected to be an OpenMP // device or host. @@ -2434,7 +2615,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // Add unsupported host targets here: case llvm::Triple::nvptx: case llvm::Triple::nvptx64: - Diags.Report(clang::diag::err_drv_omp_host_target_not_supported) + Diags.Report(diag::err_drv_omp_host_target_not_supported) << TargetOpts.Triple; break; } @@ -2443,7 +2624,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // Set the flag to prevent the implementation from emitting device exception // handling code for those requiring so. - if (Opts.OpenMPIsDevice && T.isNVPTX()) { + Opts.OpenMPHostCXXExceptions = Opts.Exceptions && Opts.CXXExceptions; + if ((Opts.OpenMPIsDevice && T.isNVPTX()) || Opts.OpenCLCPlusPlus) { Opts.Exceptions = 0; Opts.CXXExceptions = 0; } @@ -2462,7 +2644,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, TT.getArch() == llvm::Triple::nvptx64 || TT.getArch() == llvm::Triple::x86 || TT.getArch() == llvm::Triple::x86_64)) - Diags.Report(clang::diag::err_drv_invalid_omp_target) << A->getValue(i); + Diags.Report(diag::err_drv_invalid_omp_target) << A->getValue(i); else Opts.OMPTargetTriples.push_back(TT); } @@ -2473,10 +2655,14 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Arg *A = Args.getLastArg(options::OPT_fopenmp_host_ir_file_path)) { Opts.OMPHostIRFile = A->getValue(); if (!llvm::sys::fs::exists(Opts.OMPHostIRFile)) - Diags.Report(clang::diag::err_drv_omp_host_ir_file_not_found) + Diags.Report(diag::err_drv_omp_host_ir_file_not_found) << Opts.OMPHostIRFile; } + // set CUDA mode for OpenMP target NVPTX if specified in options + Opts.OpenMPCUDAMode = Opts.OpenMPIsDevice && T.isNVPTX() && + Args.hasArg(options::OPT_fopenmp_cuda_mode); + // Record whether the __DEPRECATED define was requested. Opts.Deprecated = Args.hasFlag(OPT_fdeprecated_macro, OPT_fno_deprecated_macro, @@ -2551,14 +2737,55 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Args.hasFlag(OPT_fxray_always_emit_customevents, OPT_fnoxray_always_emit_customevents, false); + // -fxray-always-emit-typedevents + Opts.XRayAlwaysEmitTypedEvents = + Args.hasFlag(OPT_fxray_always_emit_typedevents, + OPT_fnoxray_always_emit_customevents, false); + // -fxray-{always,never}-instrument= filenames. Opts.XRayAlwaysInstrumentFiles = Args.getAllArgValues(OPT_fxray_always_instrument); Opts.XRayNeverInstrumentFiles = Args.getAllArgValues(OPT_fxray_never_instrument); + Opts.XRayAttrListFiles = Args.getAllArgValues(OPT_fxray_attr_list); + + // -fforce-emit-vtables + Opts.ForceEmitVTables = Args.hasArg(OPT_fforce_emit_vtables); // -fallow-editor-placeholders Opts.AllowEditorPlaceholders = Args.hasArg(OPT_fallow_editor_placeholders); + + if (Arg *A = Args.getLastArg(OPT_fclang_abi_compat_EQ)) { + Opts.setClangABICompat(LangOptions::ClangABI::Latest); + + StringRef Ver = A->getValue(); + std::pair<StringRef, StringRef> VerParts = Ver.split('.'); + unsigned Major, Minor = 0; + + // Check the version number is valid: either 3.x (0 <= x <= 9) or + // y or y.0 (4 <= y <= current version). + if (!VerParts.first.startswith("0") && + !VerParts.first.getAsInteger(10, Major) && + 3 <= Major && Major <= CLANG_VERSION_MAJOR && + (Major == 3 ? VerParts.second.size() == 1 && + !VerParts.second.getAsInteger(10, Minor) + : VerParts.first.size() == Ver.size() || + VerParts.second == "0")) { + // Got a valid version number. + if (Major == 3 && Minor <= 8) + Opts.setClangABICompat(LangOptions::ClangABI::Ver3_8); + else if (Major <= 4) + Opts.setClangABICompat(LangOptions::ClangABI::Ver4); + else if (Major <= 6) + Opts.setClangABICompat(LangOptions::ClangABI::Ver6); + } else if (Ver != "latest") { + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(); + } + } + + Opts.CompleteMemberPointers = Args.hasArg(OPT_fcomplete_member_pointers); + Opts.BuildingPCHWithObjectFile = Args.hasArg(OPT_building_pch_with_obj); } static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { @@ -2587,9 +2814,11 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { case frontend::RewriteObjC: case frontend::RewriteTest: case frontend::RunAnalysis: + case frontend::TemplightDump: case frontend::MigrateSource: return false; + case frontend::DumpCompilerOptions: case frontend::DumpRawTokens: case frontend::DumpTokens: case frontend::InitOnly: @@ -2603,12 +2832,11 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { } static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, - FileManager &FileMgr, DiagnosticsEngine &Diags, frontend::ActionKind Action) { - using namespace options; Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch); Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth); + Opts.PCHThroughHeader = Args.getLastArgValue(OPT_pch_through_header_EQ); if (const Arg *A = Args.getLastArg(OPT_token_cache)) Opts.TokenCache = A->getValue(); else @@ -2619,7 +2847,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.AllowPCHWithCompilerErrors = Args.hasArg(OPT_fallow_pch_with_errors); Opts.DumpDeserializedPCHDecls = Args.hasArg(OPT_dump_deserialized_pch_decls); - for (const Arg *A : Args.filtered(OPT_error_on_deserialized_pch_decl)) + for (const auto *A : Args.filtered(OPT_error_on_deserialized_pch_decl)) Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue()); if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) { @@ -2638,8 +2866,19 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, } } + // Add the __CET__ macro if a CFProtection option is set. + if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) { + StringRef Name = A->getValue(); + if (Name == "branch") + Opts.addMacroDef("__CET__=1"); + else if (Name == "return") + Opts.addMacroDef("__CET__=2"); + else if (Name == "full") + Opts.addMacroDef("__CET__=3"); + } + // Add macros from the command line. - for (const Arg *A : Args.filtered(OPT_D, OPT_U)) { + for (const auto *A : Args.filtered(OPT_D, OPT_U)) { if (A->getOption().matches(OPT_D)) Opts.addMacroDef(A->getValue()); else @@ -2649,13 +2888,13 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.MacroIncludes = Args.getAllArgValues(OPT_imacros); // Add the ordered list of -includes. - for (const Arg *A : Args.filtered(OPT_include)) + for (const auto *A : Args.filtered(OPT_include)) Opts.Includes.emplace_back(A->getValue()); - for (const Arg *A : Args.filtered(OPT_chain_include)) + for (const auto *A : Args.filtered(OPT_chain_include)) Opts.ChainedIncludes.emplace_back(A->getValue()); - for (const Arg *A : Args.filtered(OPT_remap_file)) { + for (const auto *A : Args.filtered(OPT_remap_file)) { std::pair<StringRef, StringRef> Split = StringRef(A->getValue()).split(';'); if (Split.second.empty()) { @@ -2689,8 +2928,6 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, ArgList &Args, frontend::ActionKind Action) { - using namespace options; - if (isStrictlyPreprocessorAction(Action)) Opts.ShowCPP = !Args.hasArg(OPT_dM); else @@ -2708,7 +2945,6 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { - using namespace options; Opts.ABI = Args.getLastArgValue(OPT_target_abi); if (Arg *A = Args.getLastArg(OPT_meabi)) { StringRef Value = A->getValue(); @@ -2728,11 +2964,15 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args, Opts.FPMath = Args.getLastArgValue(OPT_mfpmath); Opts.FeaturesAsWritten = Args.getAllArgValues(OPT_target_feature); Opts.LinkerVersion = Args.getLastArgValue(OPT_target_linker_version); - Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple)); + Opts.Triple = Args.getLastArgValue(OPT_triple); // Use the default target triple if unspecified. if (Opts.Triple.empty()) Opts.Triple = llvm::sys::getDefaultTargetTriple(); + Opts.Triple = llvm::Triple::normalize(Opts.Triple); Opts.OpenCLExtensionsAsWritten = Args.getAllArgValues(OPT_cl_ext_EQ); + Opts.ForceEnableInt128 = Args.hasArg(OPT_fforce_enable_int128); + Opts.NVPTXUseShortPointers = Args.hasFlag( + options::OPT_fcuda_short_ptr, options::OPT_fno_cuda_short_ptr, false); } bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, @@ -2758,8 +2998,14 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, } // Issue errors on unknown arguments. - for (const Arg *A : Args.filtered(OPT_UNKNOWN)) { - Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args); + for (const auto *A : Args.filtered(OPT_UNKNOWN)) { + auto ArgString = A->getAsString(Args); + std::string Nearest; + if (Opts->findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1) + Diags.Report(diag::err_drv_unknown_argument) << ArgString; + else + Diags.Report(diag::err_drv_unknown_argument_with_suggestion) + << ArgString << Nearest; Success = false; } @@ -2776,7 +3022,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, LangOpts.IsHeaderFile); ParseTargetArgs(Res.getTargetOpts(), Args, Diags); Success &= ParseCodeGenArgs(Res.getCodeGenOpts(), Args, DashX, Diags, - Res.getTargetOpts()); + Res.getTargetOpts(), Res.getFrontendOpts()); ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args, Res.getFileSystemOpts().WorkingDir); if (DashX.getFormat() == InputKind::Precompiled || @@ -2801,6 +3047,9 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, LangOpts.ObjCExceptions = 1; } + LangOpts.FunctionAlignment = + getLastArgIntValue(Args, OPT_function_alignment, 0, Diags); + if (LangOpts.CUDA) { // During CUDA device-side compilation, the aux triple is the // triple used for host compilation. @@ -2819,12 +3068,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, !LangOpts.Sanitize.has(SanitizerKind::Address) && !LangOpts.Sanitize.has(SanitizerKind::Memory); - // FIXME: ParsePreprocessorArgs uses the FileManager to read the contents of - // PCH file and find the original header name. Remove the need to do that in - // ParsePreprocessorArgs and remove the FileManager - // parameters from the function and the "FileManager.h" #include. - FileManager FileMgr(Res.getFileSystemOpts()); - ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, FileMgr, Diags, + ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, Diags, Res.getFrontendOpts().ProgramAction); ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), Args, Res.getFrontendOpts().ProgramAction); @@ -2872,29 +3116,26 @@ std::string CompilerInvocation::getModuleHash() const { // Extend the signature with the target options. code = hash_combine(code, TargetOpts->Triple, TargetOpts->CPU, TargetOpts->ABI); - for (unsigned i = 0, n = TargetOpts->FeaturesAsWritten.size(); i != n; ++i) - code = hash_combine(code, TargetOpts->FeaturesAsWritten[i]); + for (const auto &FeatureAsWritten : TargetOpts->FeaturesAsWritten) + code = hash_combine(code, FeatureAsWritten); // Extend the signature with preprocessor options. const PreprocessorOptions &ppOpts = getPreprocessorOpts(); const HeaderSearchOptions &hsOpts = getHeaderSearchOpts(); code = hash_combine(code, ppOpts.UsePredefines, ppOpts.DetailedRecord); - for (std::vector<std::pair<std::string, bool/*isUndef*/>>::const_iterator - I = getPreprocessorOpts().Macros.begin(), - IEnd = getPreprocessorOpts().Macros.end(); - I != IEnd; ++I) { + for (const auto &I : getPreprocessorOpts().Macros) { // If we're supposed to ignore this macro for the purposes of modules, // don't put it into the hash. if (!hsOpts.ModulesIgnoreMacros.empty()) { // Check whether we're ignoring this macro. - StringRef MacroDef = I->first; + StringRef MacroDef = I.first; if (hsOpts.ModulesIgnoreMacros.count( llvm::CachedHashString(MacroDef.split('=').first))) continue; } - code = hash_combine(code, I->first, I->second); + code = hash_combine(code, I.first, I.second); } // Extend the signature with the sysroot and other header search options. @@ -2927,8 +3168,6 @@ std::string CompilerInvocation::getModuleHash() const { return llvm::APInt(64, code).toString(36, /*Signed=*/false); } -namespace clang { - template<typename IntTy> static IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id, IntTy Default, @@ -2944,6 +3183,7 @@ static IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id, return Res; } +namespace clang { // Declared in clang/Frontend/Utils.h. int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default, @@ -2988,22 +3228,22 @@ createVFSFromCompilerInvocation(const CompilerInvocation &CI, IntrusiveRefCntPtr<vfs::OverlayFileSystem> Overlay( new vfs::OverlayFileSystem(BaseFS)); // earlier vfs files are on the bottom - for (const std::string &File : CI.getHeaderSearchOpts().VFSOverlayFiles) { + for (const auto &File : CI.getHeaderSearchOpts().VFSOverlayFiles) { llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer = BaseFS->getBufferForFile(File); if (!Buffer) { Diags.Report(diag::err_missing_vfs_overlay_file) << File; - return IntrusiveRefCntPtr<vfs::FileSystem>(); + continue; } IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getVFSFromYAML( std::move(Buffer.get()), /*DiagHandler*/ nullptr, File); - if (!FS.get()) { + if (FS) + Overlay->pushOverlay(FS); + else Diags.Report(diag::err_invalid_vfs_overlay) << File; - return IntrusiveRefCntPtr<vfs::FileSystem>(); - } - Overlay->pushOverlay(FS); } return Overlay; } -} // end namespace clang + +} // namespace clang diff --git a/gnu/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp b/gnu/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp index 2efbfaae92b..a3901e5fb91 100644 --- a/gnu/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp +++ b/gnu/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp @@ -14,6 +14,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/LangOptions.h" #include "clang/Config/config.h" // C_INCLUDE_DIRS +#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/Utils.h" #include "clang/Lex/HeaderMap.h" #include "clang/Lex/HeaderSearch.h" @@ -55,11 +56,13 @@ public: /// AddPath - Add the specified path to the specified group list, prefixing /// the sysroot if used. - void AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework); + /// Returns true if the path exists, false if it was ignored. + bool AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework); /// AddUnmappedPath - Add the specified path to the specified group list, /// without performing any sysroot remapping. - void AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, + /// Returns true if the path exists, false if it was ignored. + bool AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, bool isFramework); /// AddSystemHeaderPrefix - Add the specified prefix to the system header @@ -70,10 +73,9 @@ public: /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to support a gnu /// libstdc++. - void AddGnuCPlusPlusIncludePaths(StringRef Base, - StringRef ArchDir, - StringRef Dir32, - StringRef Dir64, + /// Returns true if the \p Base path was found, false if it does not exist. + bool AddGnuCPlusPlusIncludePaths(StringRef Base, StringRef ArchDir, + StringRef Dir32, StringRef Dir64, const llvm::Triple &triple); /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to support a MinGW @@ -88,7 +90,8 @@ public: // AddDefaultCPlusPlusIncludePaths - Add paths that should be searched when // compiling c++. - void AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, + void AddDefaultCPlusPlusIncludePaths(const LangOptions &LangOpts, + const llvm::Triple &triple, const HeaderSearchOptions &HSOpts); /// AddDefaultSystemIncludePaths - Adds the default system include paths so @@ -105,14 +108,14 @@ public: } // end anonymous namespace. static bool CanPrefixSysroot(StringRef Path) { -#if defined(LLVM_ON_WIN32) +#if defined(_WIN32) return !Path.empty() && llvm::sys::path::is_separator(Path[0]); #else return llvm::sys::path::is_absolute(Path); #endif } -void InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group, +bool InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework) { // Add the path with sysroot prepended, if desired and this is a system header // group. @@ -120,15 +123,14 @@ void InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group, SmallString<256> MappedPathStorage; StringRef MappedPathStr = Path.toStringRef(MappedPathStorage); if (CanPrefixSysroot(MappedPathStr)) { - AddUnmappedPath(IncludeSysroot + Path, Group, isFramework); - return; + return AddUnmappedPath(IncludeSysroot + Path, Group, isFramework); } } - AddUnmappedPath(Path, Group, isFramework); + return AddUnmappedPath(Path, Group, isFramework); } -void InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, +bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, bool isFramework) { assert(!Path.isTriviallyEmpty() && "can't handle empty path here"); @@ -150,7 +152,7 @@ void InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, if (const DirectoryEntry *DE = FM.getDirectory(MappedPathStr)) { IncludePath.push_back( std::make_pair(Group, DirectoryLookup(DE, Type, isFramework))); - return; + return true; } // Check to see if this is an apple-style headermap (which are not allowed to @@ -162,7 +164,7 @@ void InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, IncludePath.push_back( std::make_pair(Group, DirectoryLookup(HM, Type, Group == IndexHeaderMap))); - return; + return true; } } } @@ -170,15 +172,16 @@ void InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, if (Verbose) llvm::errs() << "ignoring nonexistent directory \"" << MappedPathStr << "\"\n"; + return false; } -void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(StringRef Base, +bool InitHeaderSearch::AddGnuCPlusPlusIncludePaths(StringRef Base, StringRef ArchDir, StringRef Dir32, StringRef Dir64, const llvm::Triple &triple) { // Add the base dir - AddPath(Base, CXXSystem, false); + bool IsBaseFound = AddPath(Base, CXXSystem, false); // Add the multilib dirs llvm::Triple::ArchType arch = triple.getArch(); @@ -190,6 +193,7 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(StringRef Base, // Add the backward dir AddPath(Base + "/backward", CXXSystem, false); + return IsBaseFound; } void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(StringRef Base, @@ -216,6 +220,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, case llvm::Triple::NaCl: case llvm::Triple::PS4: case llvm::Triple::ELFIAMCU: + case llvm::Triple::Fuchsia: break; case llvm::Triple::Win32: if (triple.getEnvironment() != llvm::Triple::Cygnus) @@ -255,6 +260,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, switch (os) { case llvm::Triple::Linux: + case llvm::Triple::Solaris: llvm_unreachable("Include management is handled in the driver."); case llvm::Triple::CloudABI: { @@ -321,6 +327,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, case llvm::Triple::RTEMS: case llvm::Triple::NaCl: case llvm::Triple::ELFIAMCU: + case llvm::Triple::Fuchsia: break; case llvm::Triple::PS4: { // <isysroot> gets prepended later in AddPath(). @@ -351,51 +358,61 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, } } -void InitHeaderSearch:: -AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOptions &HSOpts) { +void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths( + const LangOptions &LangOpts, const llvm::Triple &triple, + const HeaderSearchOptions &HSOpts) { llvm::Triple::OSType os = triple.getOS(); // FIXME: temporary hack: hard-coded paths. if (triple.isOSDarwin()) { + bool IsBaseFound = true; switch (triple.getArch()) { default: break; case llvm::Triple::ppc: case llvm::Triple::ppc64: - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", - "powerpc-apple-darwin10", "", "ppc64", - triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0", - "powerpc-apple-darwin10", "", "ppc64", - triple); + IsBaseFound = AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", + "powerpc-apple-darwin10", "", + "ppc64", triple); + IsBaseFound |= AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0", + "powerpc-apple-darwin10", "", + "ppc64", triple); break; case llvm::Triple::x86: case llvm::Triple::x86_64: - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", - "i686-apple-darwin10", "", "x86_64", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0", - "i686-apple-darwin8", "", "", triple); + IsBaseFound = AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", + "i686-apple-darwin10", "", + "x86_64", triple); + IsBaseFound |= AddGnuCPlusPlusIncludePaths( + "/usr/include/c++/4.0.0", "i686-apple-darwin8", "", "", triple); break; case llvm::Triple::arm: case llvm::Triple::thumb: - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", - "arm-apple-darwin10", "v7", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", - "arm-apple-darwin10", "v6", "", triple); + IsBaseFound = AddGnuCPlusPlusIncludePaths( + "/usr/include/c++/4.2.1", "arm-apple-darwin10", "v7", "", triple); + IsBaseFound |= AddGnuCPlusPlusIncludePaths( + "/usr/include/c++/4.2.1", "arm-apple-darwin10", "v6", "", triple); break; case llvm::Triple::aarch64: - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", - "arm64-apple-darwin10", "", "", triple); + IsBaseFound = AddGnuCPlusPlusIncludePaths( + "/usr/include/c++/4.2.1", "arm64-apple-darwin10", "", "", triple); break; } + // Warn when compiling pure C++ / Objective-C++ only. + if (!IsBaseFound && + !(LangOpts.CUDA || LangOpts.OpenCL || LangOpts.RenderScript)) { + Headers.getDiags().Report(SourceLocation(), + diag::warn_stdlibcxx_not_found); + } return; } switch (os) { case llvm::Triple::Linux: + case llvm::Triple::Solaris: llvm_unreachable("Include management is handled in the driver."); break; case llvm::Triple::Win32: @@ -435,6 +452,7 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang, break; // Everything else continues to use this routine's logic. case llvm::Triple::Linux: + case llvm::Triple::Solaris: return; case llvm::Triple::Win32: @@ -444,8 +462,8 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang, break; } - if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes && - HSOpts.UseStandardSystemIncludes) { + if (Lang.CPlusPlus && !Lang.AsmPreprocessor && + HSOpts.UseStandardCXXIncludes && HSOpts.UseStandardSystemIncludes) { if (HSOpts.UseLibcxx) { if (triple.isOSDarwin()) { // On Darwin, libc++ may be installed alongside the compiler in @@ -465,7 +483,7 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang, } AddPath("/usr/include/c++/v1", CXXSystem, false); } else { - AddDefaultCPlusPlusIncludePaths(triple, HSOpts); + AddDefaultCPlusPlusIncludePaths(Lang, triple, HSOpts); } } diff --git a/gnu/llvm/tools/clang/lib/Sema/SemaChecking.cpp b/gnu/llvm/tools/clang/lib/Sema/SemaChecking.cpp index 30e693b558d..03057defd95 100644 --- a/gnu/llvm/tools/clang/lib/Sema/SemaChecking.cpp +++ b/gnu/llvm/tools/clang/lib/Sema/SemaChecking.cpp @@ -28,6 +28,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" #include "clang/AST/NSAPI.h" +#include "clang/AST/NonTrivialTypeVisitor.h" #include "clang/AST/OperationKinds.h" #include "clang/AST/Stmt.h" #include "clang/AST/TemplateBase.h" @@ -118,7 +119,7 @@ static bool checkArgCount(Sema &S, CallExpr *call, unsigned desiredArgCount) { // Highlight all the excess arguments. SourceRange range(call->getArg(desiredArgCount)->getLocStart(), call->getArg(argCount - 1)->getLocEnd()); - + return S.Diag(range.getBegin(), diag::err_typecheck_call_too_many_args) << 0 /*function call*/ << desiredArgCount << argCount << call->getArg(1)->getSourceRange(); @@ -196,35 +197,47 @@ static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall) { // First two arguments should be integers. for (unsigned I = 0; I < 2; ++I) { - Expr *Arg = TheCall->getArg(I); - QualType Ty = Arg->getType(); + ExprResult Arg = TheCall->getArg(I); + QualType Ty = Arg.get()->getType(); if (!Ty->isIntegerType()) { - S.Diag(Arg->getLocStart(), diag::err_overflow_builtin_must_be_int) - << Ty << Arg->getSourceRange(); + S.Diag(Arg.get()->getLocStart(), diag::err_overflow_builtin_must_be_int) + << Ty << Arg.get()->getSourceRange(); return true; } + InitializedEntity Entity = InitializedEntity::InitializeParameter( + S.getASTContext(), Ty, /*consume*/ false); + Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); + if (Arg.isInvalid()) + return true; + TheCall->setArg(I, Arg.get()); } // Third argument should be a pointer to a non-const integer. // IRGen correctly handles volatile, restrict, and address spaces, and // the other qualifiers aren't possible. { - Expr *Arg = TheCall->getArg(2); - QualType Ty = Arg->getType(); + ExprResult Arg = TheCall->getArg(2); + QualType Ty = Arg.get()->getType(); const auto *PtrTy = Ty->getAs<PointerType>(); if (!(PtrTy && PtrTy->getPointeeType()->isIntegerType() && !PtrTy->getPointeeType().isConstQualified())) { - S.Diag(Arg->getLocStart(), diag::err_overflow_builtin_must_be_ptr_int) - << Ty << Arg->getSourceRange(); + S.Diag(Arg.get()->getLocStart(), + diag::err_overflow_builtin_must_be_ptr_int) + << Ty << Arg.get()->getSourceRange(); return true; } + InitializedEntity Entity = InitializedEntity::InitializeParameter( + S.getASTContext(), Ty, /*consume*/ false); + Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); + if (Arg.isInvalid()) + return true; + TheCall->setArg(2, Arg.get()); } - return false; } static void SemaBuiltinMemChkCall(Sema &S, FunctionDecl *FDecl, - CallExpr *TheCall, unsigned SizeIdx, + CallExpr *TheCall, unsigned SizeIdx, unsigned DstSizeIdx) { if (TheCall->getNumArgs() <= SizeIdx || TheCall->getNumArgs() <= DstSizeIdx) @@ -683,7 +696,7 @@ static bool checkOpenCLPipePacketType(Sema &S, CallExpr *Call, unsigned Idx) { return false; } -// \brief Performs semantic analysis for the read/write_pipe call. +// Performs semantic analysis for the read/write_pipe call. // \param S Reference to the semantic analyzer. // \param Call A pointer to the builtin call. // \return True if a semantic error has been found, false otherwise. @@ -737,7 +750,7 @@ static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) { return false; } -// \brief Performs a semantic analysis on the {work_group_/sub_group_ +// Performs a semantic analysis on the {work_group_/sub_group_ // /_}reserve_{read/write}_pipe // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. @@ -766,7 +779,7 @@ static bool SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) { return false; } -// \brief Performs a semantic analysis on {work_group_/sub_group_ +// Performs a semantic analysis on {work_group_/sub_group_ // /_}commit_{read/write}_pipe // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. @@ -789,7 +802,7 @@ static bool SemaBuiltinCommitRWPipe(Sema &S, CallExpr *Call) { return false; } -// \brief Performs a semantic analysis on the call to built-in Pipe +// Performs a semantic analysis on the call to built-in Pipe // Query Functions. // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. @@ -807,8 +820,8 @@ static bool SemaBuiltinPipePackets(Sema &S, CallExpr *Call) { return false; } -// \brief OpenCL v2.0 s6.13.9 - Address space qualifier functions. -// \brief Performs semantic analysis for the to_global/local/private call. +// OpenCL v2.0 s6.13.9 - Address space qualifier functions. +// Performs semantic analysis for the to_global/local/private call. // \param S Reference to the semantic analyzer. // \param BuiltinID ID of the builtin function. // \param Call A pointer to the builtin call. @@ -850,6 +863,20 @@ static bool SemaOpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID, return false; } +// Emit an error and return true if the current architecture is not in the list +// of supported architectures. +static bool +CheckBuiltinTargetSupport(Sema &S, unsigned BuiltinID, CallExpr *TheCall, + ArrayRef<llvm::Triple::ArchType> SupportedArchs) { + llvm::Triple::ArchType CurArch = + S.getASTContext().getTargetInfo().getTriple().getArch(); + if (llvm::is_contained(SupportedArchs, CurArch)) + return false; + S.Diag(TheCall->getLocStart(), diag::err_builtin_target_unsupported) + << TheCall->getSourceRange(); + return true; +} + ExprResult Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall) { @@ -861,18 +888,18 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, Context.GetBuiltinType(BuiltinID, Error, &ICEArguments); if (Error != ASTContext::GE_None) ICEArguments = 0; // Don't diagnose previously diagnosed errors. - + // If any arguments are required to be ICE's, check and diagnose. for (unsigned ArgNo = 0; ICEArguments != 0; ++ArgNo) { // Skip arguments not required to be ICE's. if ((ICEArguments & (1 << ArgNo)) == 0) continue; - + llvm::APSInt Result; if (SemaBuiltinConstantArg(TheCall, ArgNo, Result)) return true; ICEArguments &= ~(1 << ArgNo); } - + switch (BuiltinID) { case Builtin::BI__builtin___CFStringMakeConstantString: assert(TheCall->getNumArgs() == 1 && @@ -900,6 +927,33 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, } break; } + + // The acquire, release, and no fence variants are ARM and AArch64 only. + case Builtin::BI_interlockedbittestandset_acq: + case Builtin::BI_interlockedbittestandset_rel: + case Builtin::BI_interlockedbittestandset_nf: + case Builtin::BI_interlockedbittestandreset_acq: + case Builtin::BI_interlockedbittestandreset_rel: + case Builtin::BI_interlockedbittestandreset_nf: + if (CheckBuiltinTargetSupport( + *this, BuiltinID, TheCall, + {llvm::Triple::arm, llvm::Triple::thumb, llvm::Triple::aarch64})) + return ExprError(); + break; + + // The 64-bit bittest variants are x64, ARM, and AArch64 only. + case Builtin::BI_bittest64: + case Builtin::BI_bittestandcomplement64: + case Builtin::BI_bittestandreset64: + case Builtin::BI_bittestandset64: + case Builtin::BI_interlockedbittestandreset64: + case Builtin::BI_interlockedbittestandset64: + if (CheckBuiltinTargetSupport(*this, BuiltinID, TheCall, + {llvm::Triple::x86_64, llvm::Triple::arm, + llvm::Triple::thumb, llvm::Triple::aarch64})) + return ExprError(); + break; + case Builtin::BI__builtin_isgreater: case Builtin::BI__builtin_isgreaterequal: case Builtin::BI__builtin_isless: @@ -918,6 +972,9 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_isinf_sign: case Builtin::BI__builtin_isnan: case Builtin::BI__builtin_isnormal: + case Builtin::BI__builtin_signbit: + case Builtin::BI__builtin_signbitf: + case Builtin::BI__builtin_signbitl: if (SemaBuiltinFPClassification(TheCall, 1)) return ExprError(); break; @@ -1097,19 +1154,70 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); break; case Builtin::BI__builtin_operator_new: - case Builtin::BI__builtin_operator_delete: - if (!getLangOpts().CPlusPlus) { - Diag(TheCall->getExprLoc(), diag::err_builtin_requires_language) - << (BuiltinID == Builtin::BI__builtin_operator_new - ? "__builtin_operator_new" - : "__builtin_operator_delete") - << "C++"; + case Builtin::BI__builtin_operator_delete: { + bool IsDelete = BuiltinID == Builtin::BI__builtin_operator_delete; + ExprResult Res = + SemaBuiltinOperatorNewDeleteOverloaded(TheCallResult, IsDelete); + if (Res.isInvalid()) + CorrectDelayedTyposInExpr(TheCallResult.get()); + return Res; + } + case Builtin::BI__builtin_dump_struct: { + // We first want to ensure we are called with 2 arguments + if (checkArgCount(*this, TheCall, 2)) + return ExprError(); + // Ensure that the first argument is of type 'struct XX *' + const Expr *PtrArg = TheCall->getArg(0)->IgnoreParenImpCasts(); + const QualType PtrArgType = PtrArg->getType(); + if (!PtrArgType->isPointerType() || + !PtrArgType->getPointeeType()->isRecordType()) { + Diag(PtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << PtrArgType << "structure pointer" << 1 << 0 << 3 << 1 << PtrArgType + << "structure pointer"; + return ExprError(); + } + + // Ensure that the second argument is of type 'FunctionType' + const Expr *FnPtrArg = TheCall->getArg(1)->IgnoreImpCasts(); + const QualType FnPtrArgType = FnPtrArg->getType(); + if (!FnPtrArgType->isPointerType()) { + Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 + << 2 << FnPtrArgType << "'int (*)(const char *, ...)'"; return ExprError(); } - // CodeGen assumes it can find the global new and delete to call, - // so ensure that they are declared. - DeclareGlobalNewDelete(); + + const auto *FuncType = + FnPtrArgType->getPointeeType()->getAs<FunctionType>(); + + if (!FuncType) { + Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 + << 2 << FnPtrArgType << "'int (*)(const char *, ...)'"; + return ExprError(); + } + + if (const auto *FT = dyn_cast<FunctionProtoType>(FuncType)) { + if (!FT->getNumParams()) { + Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 + << 2 << FnPtrArgType << "'int (*)(const char *, ...)'"; + return ExprError(); + } + QualType PT = FT->getParamType(0); + if (!FT->isVariadic() || FT->getReturnType() != Context.IntTy || + !PT->isPointerType() || !PT->getPointeeType()->isCharType() || + !PT->getPointeeType().isConstQualified()) { + Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 + << 2 << FnPtrArgType << "'int (*)(const char *, ...)'"; + return ExprError(); + } + } + + TheCall->setType(Context.IntTy); break; + } // check secure string manipulation functions where overflows // are detectable at compile time @@ -1215,7 +1323,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaOpenCLBuiltinKernelWorkGroupSize(*this, TheCall)) return ExprError(); break; - break; case Builtin::BIget_kernel_max_sub_group_size_for_ndrange: case Builtin::BIget_kernel_sub_group_count_for_ndrange: if (SemaOpenCLBuiltinNDRangeAndBlock(*this, TheCall)) @@ -1244,6 +1351,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; + case llvm::Triple::hexagon: + if (CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall)) + return ExprError(); + break; case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: @@ -1353,6 +1464,7 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { switch (BuiltinID) { #define GET_NEON_OVERLOAD_CHECK #include "clang/Basic/arm_neon.inc" +#include "clang/Basic/arm_fp16.inc" #undef GET_NEON_OVERLOAD_CHECK } @@ -1402,9 +1514,10 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { switch (BuiltinID) { default: return false; -#define GET_NEON_IMMEDIATE_CHECK -#include "clang/Basic/arm_neon.inc" -#undef GET_NEON_IMMEDIATE_CHECK + #define GET_NEON_IMMEDIATE_CHECK + #include "clang/Basic/arm_neon.inc" + #include "clang/Basic/arm_fp16.inc" + #undef GET_NEON_IMMEDIATE_CHECK } return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); @@ -1618,6 +1731,1015 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); } +bool Sema::CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) { + static const std::map<unsigned, std::vector<StringRef>> ValidCPU = { + { Hexagon::BI__builtin_HEXAGON_A6_vcmpbeq_notany, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_A6_vminub_RdP, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_M6_vabsdiffb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_M6_vabsdiffub, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_nac, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_xacc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_nac, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_xacc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_vsplatrbp, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_vtrunehb_ppp, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_vtrunohb_ppp, {"v62", "v65"} }, + }; + + static const std::map<unsigned, std::vector<StringRef>> ValidHVX = { + { Hexagon::BI__builtin_HEXAGON_V6_extractw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_extractw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_hi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_hi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lo, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lo_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplatb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplatb_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplath, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplath_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplatw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplatw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_and_n, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_and_n_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_not, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_not_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_or_n, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_or_n_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2v2, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2v2_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_shuffeqh, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_shuffeqh_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_shuffeqw, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_shuffeqw_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsb, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsb_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsb_sat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsb_sat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsh_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsh_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsw_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsw_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddb_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddb_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat_dv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat_dv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddcarry, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddcarry_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddclbh, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddclbh_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddclbw, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddclbw_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddh_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddh_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhw_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhw_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubh_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubh_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddububb_sat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddububb_sat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhw_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhw_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat_dv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat_dv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddw_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddw_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignbi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignbi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vand, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vand_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandqrt, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandqrt_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandqrt_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandqrt_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvnqv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvnqv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvqv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvqv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvrt, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvrt_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvrt_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvrt_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslh_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslh_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslhv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslhv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslw_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslw_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslwv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslwv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrh_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrh_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhbrndsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhbrndsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhbsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhbsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhubrndsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhubrndsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhubsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhubsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruhubrndsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruhubrndsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruhubsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruhubsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhrndsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhrndsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrw_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrw_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwhrndsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwhrndsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhrndsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhrndsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vassign, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vassign_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vassignp, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vassignp_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgb, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgb_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgbrnd, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgbrnd_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavghrnd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavghrnd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgubrnd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgubrnd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguhrnd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguhrnd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguw, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguw_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguwrnd, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguwrnd_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgwrnd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgwrnd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcl0h, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcl0h_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcl0w, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcl0w_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcombine, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcombine_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vd0, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vd0_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdd0, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdd0_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealb4w, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealb4w_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealvdd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealvdd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdelta, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdelta_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vinsertwr, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vinsertwr_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrb_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrhv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrhv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrwv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrwv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlut4, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlut4_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_nm, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_nm_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_nm, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_nm_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxb_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminb_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabusv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabusv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuuv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuuv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahhsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahhsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhuhsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhuhsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpsuhuhsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpsuhuhsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh_64, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh_64_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyh_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyh_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsrs, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsrs_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhss, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhss_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhvsrs, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhvsrs_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyieoh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyieoh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewh_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewh_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyih, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyih_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyih_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyih_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiowh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiowh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_64_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_64_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd_sacc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd_sacc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_sacc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_sacc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyub_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyub_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmux, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmux_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgb, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgb_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnormamth, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnormamth_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnormamtw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnormamtw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnot, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnot_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackeb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackeb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackeh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackeh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackhb_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackhb_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackhub_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackhub_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackob, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackob_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackoh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackoh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackwh_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackwh_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackwuh_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackwuh_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpopcounth, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpopcounth_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqb, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqb_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqh, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqh_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqw, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqw_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrdelta, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrdelta_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vror, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vror_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundhb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundhb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundhub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundhub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrounduhub, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrounduhub_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrounduwuh, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrounduwuh_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundwh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundwh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundwuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundwuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsathub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsathub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsatuwuh, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsatuwuh_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsatwh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsatwh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufeh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufeh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffeb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffeb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffob, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffob_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffvdd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffvdd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoeb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoeb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoeh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoeh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubb_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubb_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat_dv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat_dv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubcarry, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubcarry_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubh_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubh_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubububb_sat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubububb_sat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat_dv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat_dv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubw_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubw_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vswap, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vswap_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackob, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackob_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackoh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackoh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vxor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vxor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vzb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vzb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vzh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vzh_128B, {"v60", "v62", "v65"} }, + }; + + const TargetInfo &TI = Context.getTargetInfo(); + + auto FC = ValidCPU.find(BuiltinID); + if (FC != ValidCPU.end()) { + const TargetOptions &Opts = TI.getTargetOpts(); + StringRef CPU = Opts.CPU; + if (!CPU.empty()) { + assert(CPU.startswith("hexagon") && "Unexpected CPU name"); + CPU.consume_front("hexagon"); + if (llvm::none_of(FC->second, [CPU](StringRef S) { return S == CPU; })) + return Diag(TheCall->getLocStart(), + diag::err_hexagon_builtin_unsupported_cpu); + } + } + + auto FH = ValidHVX.find(BuiltinID); + if (FH != ValidHVX.end()) { + if (!TI.hasFeature("hvx")) + return Diag(TheCall->getLocStart(), + diag::err_hexagon_builtin_requires_hvx); + + bool IsValid = llvm::any_of(FH->second, + [&TI] (StringRef V) { + std::string F = "hvx" + V.str(); + return TI.hasFeature(F); + }); + if (!IsValid) + return Diag(TheCall->getLocStart(), + diag::err_hexagon_builtin_unsupported_hvx); + } + + return false; +} + +bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { + struct ArgInfo { + ArgInfo(unsigned O, bool S, unsigned W, unsigned A) + : OpNum(O), IsSigned(S), BitWidth(W), Align(A) {} + unsigned OpNum = 0; + bool IsSigned = false; + unsigned BitWidth = 0; + unsigned Align = 0; + }; + + static const std::map<unsigned, std::vector<ArgInfo>> Infos = { + { Hexagon::BI__builtin_circ_ldd, {{ 3, true, 4, 3 }} }, + { Hexagon::BI__builtin_circ_ldw, {{ 3, true, 4, 2 }} }, + { Hexagon::BI__builtin_circ_ldh, {{ 3, true, 4, 1 }} }, + { Hexagon::BI__builtin_circ_lduh, {{ 3, true, 4, 0 }} }, + { Hexagon::BI__builtin_circ_ldb, {{ 3, true, 4, 0 }} }, + { Hexagon::BI__builtin_circ_ldub, {{ 3, true, 4, 0 }} }, + { Hexagon::BI__builtin_circ_std, {{ 3, true, 4, 3 }} }, + { Hexagon::BI__builtin_circ_stw, {{ 3, true, 4, 2 }} }, + { Hexagon::BI__builtin_circ_sth, {{ 3, true, 4, 1 }} }, + { Hexagon::BI__builtin_circ_sthhi, {{ 3, true, 4, 1 }} }, + { Hexagon::BI__builtin_circ_stb, {{ 3, true, 4, 0 }} }, + + { Hexagon::BI__builtin_HEXAGON_L2_loadrub_pci, {{ 1, true, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadrb_pci, {{ 1, true, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadruh_pci, {{ 1, true, 4, 1 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadrh_pci, {{ 1, true, 4, 1 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadri_pci, {{ 1, true, 4, 2 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadrd_pci, {{ 1, true, 4, 3 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storerb_pci, {{ 1, true, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storerh_pci, {{ 1, true, 4, 1 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storerf_pci, {{ 1, true, 4, 1 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storeri_pci, {{ 1, true, 4, 2 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storerd_pci, {{ 1, true, 4, 3 }} }, + + { Hexagon::BI__builtin_HEXAGON_A2_combineii, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A2_tfrih, {{ 1, false, 16, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A2_tfril, {{ 1, false, 16, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A2_tfrpi, {{ 0, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_bitspliti, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_cmpbeqi, {{ 1, false, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_cmpbgti, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_cround_ri, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_round_ri, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_round_ri_sat, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpbeqi, {{ 1, false, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpbgti, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpbgtui, {{ 1, false, 7, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpheqi, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmphgti, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmphgtui, {{ 1, false, 7, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpweqi, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpwgti, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpwgtui, {{ 1, false, 7, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_C2_bitsclri, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_C2_muxii, {{ 2, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_C4_nbitsclri, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_dfclass, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_dfimm_n, {{ 0, false, 10, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_dfimm_p, {{ 0, false, 10, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_sfclass, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_sfimm_n, {{ 0, false, 10, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_sfimm_p, {{ 0, false, 10, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_M4_mpyri_addi, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_M4_mpyri_addr_u2, {{ 1, false, 6, 2 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_addasl_rrri, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_acc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_and, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_nac, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_or, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_xacc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_acc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_and, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_nac, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_or, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_sat, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_xacc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_vh, {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_vw, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_acc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_and, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_nac, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_or, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_rnd_goodsyntax, + {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_rnd, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_acc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_and, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_nac, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_or, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_rnd_goodsyntax, + {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_rnd, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_svw_trun, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_vh, {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_vw, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_clrbit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_extractu, {{ 1, false, 5, 0 }, + { 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_extractup, {{ 1, false, 6, 0 }, + { 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_insert, {{ 2, false, 5, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_insertp, {{ 2, false, 6, 0 }, + { 3, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_acc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_and, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_nac, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_or, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_xacc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_acc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_and, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_nac, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_or, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_xacc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_vh, {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_vw, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_setbit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tableidxb_goodsyntax, + {{ 2, false, 4, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tableidxd_goodsyntax, + {{ 2, false, 4, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tableidxh_goodsyntax, + {{ 2, false, 4, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tableidxw_goodsyntax, + {{ 2, false, 4, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_togglebit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tstbit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_valignib, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_vspliceib, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_addi_asl_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_addi_lsr_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_andi_asl_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_andi_lsr_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_clbaddi, {{ 1, true , 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_clbpaddi, {{ 1, true, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_extract, {{ 1, false, 5, 0 }, + { 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_extractp, {{ 1, false, 6, 0 }, + { 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_lsli, {{ 0, true, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_ntstbit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_ori_asl_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_ori_lsr_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_subi_asl_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_subi_lsr_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_vrcrotate_acc, {{ 3, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_vrcrotate, {{ 2, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S5_asrhub_rnd_sat_goodsyntax, + {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S5_asrhub_sat, {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S5_vasrhrnd_goodsyntax, + {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_acc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_and, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_nac, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_or, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_xacc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_acc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_and, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_nac, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_or, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_xacc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignbi, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignbi_128B, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi_128B, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_128B, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc, {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc_128B, + {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_128B, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc, {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc_128B, + {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_128B, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc, {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc_128B, + {{ 3, false, 1, 0 }} }, + }; + + auto F = Infos.find(BuiltinID); + if (F == Infos.end()) + return false; + + bool Error = false; + + for (const ArgInfo &A : F->second) { + int32_t Min = A.IsSigned ? -(1 << (A.BitWidth-1)) : 0; + int32_t Max = (1 << (A.IsSigned ? A.BitWidth-1 : A.BitWidth)) - 1; + if (!A.Align) { + Error |= SemaBuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); + } else { + unsigned M = 1 << A.Align; + Min *= M; + Max *= M; + Error |= SemaBuiltinConstantArgRange(TheCall, A.OpNum, Min, Max) | + SemaBuiltinConstantArgMultiple(TheCall, A.OpNum, M); + } + } + return Error; +} + +bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + return CheckHexagonBuiltinCpu(BuiltinID, TheCall) || + CheckHexagonBuiltinArgument(BuiltinID, TheCall); +} + + // CheckMipsBuiltinFunctionCall - Checks the constant value passed to the // intrinsic is correct. The switch statement is ordered by DSP, MSA. The // ordering for DSP is unspecified. MSA is ordered by the data format used @@ -1666,7 +2788,7 @@ bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case Mips::BI__builtin_msa_srlri_h: i = 1; l = 0; u = 15; break; case Mips::BI__builtin_msa_binsli_h: case Mips::BI__builtin_msa_binsri_h: i = 2; l = 0; u = 15; break; - // These intrinsics take an unsigned 5 bit immedate. + // These intrinsics take an unsigned 5 bit immediate. // The first block of intrinsics actually have an unsigned 5 bit field, // not a df/n field. case Mips::BI__builtin_msa_clei_u_b: @@ -1966,6 +3088,12 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_vcvttss2usi64: ArgNum = 1; break; + case X86::BI__builtin_ia32_maxpd512: + case X86::BI__builtin_ia32_maxps512: + case X86::BI__builtin_ia32_minpd512: + case X86::BI__builtin_ia32_minps512: + ArgNum = 2; + break; case X86::BI__builtin_ia32_cvtps2pd512_mask: case X86::BI__builtin_ia32_cvttpd2dq512_mask: case X86::BI__builtin_ia32_cvttpd2qq512_mask: @@ -1995,12 +3123,8 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cvtss2sd_round_mask: case X86::BI__builtin_ia32_getexpsd128_round_mask: case X86::BI__builtin_ia32_getexpss128_round_mask: - case X86::BI__builtin_ia32_maxpd512_mask: - case X86::BI__builtin_ia32_maxps512_mask: case X86::BI__builtin_ia32_maxsd_round_mask: case X86::BI__builtin_ia32_maxss_round_mask: - case X86::BI__builtin_ia32_minpd512_mask: - case X86::BI__builtin_ia32_minps512_mask: case X86::BI__builtin_ia32_minsd_round_mask: case X86::BI__builtin_ia32_minss_round_mask: case X86::BI__builtin_ia32_rcp28sd_round_mask: @@ -2039,9 +3163,19 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_vcvtss2si64: case X86::BI__builtin_ia32_vcvtss2usi32: case X86::BI__builtin_ia32_vcvtss2usi64: + case X86::BI__builtin_ia32_sqrtpd512: + case X86::BI__builtin_ia32_sqrtps512: ArgNum = 1; HasRC = true; break; + case X86::BI__builtin_ia32_addpd512: + case X86::BI__builtin_ia32_addps512: + case X86::BI__builtin_ia32_divpd512: + case X86::BI__builtin_ia32_divps512: + case X86::BI__builtin_ia32_mulpd512: + case X86::BI__builtin_ia32_mulps512: + case X86::BI__builtin_ia32_subpd512: + case X86::BI__builtin_ia32_subps512: case X86::BI__builtin_ia32_cvtsi2sd64: case X86::BI__builtin_ia32_cvtsi2ss32: case X86::BI__builtin_ia32_cvtsi2ss64: @@ -2062,19 +3196,9 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cvtqq2ps512_mask: case X86::BI__builtin_ia32_cvtuqq2pd512_mask: case X86::BI__builtin_ia32_cvtuqq2ps512_mask: - case X86::BI__builtin_ia32_sqrtpd512_mask: - case X86::BI__builtin_ia32_sqrtps512_mask: ArgNum = 3; HasRC = true; break; - case X86::BI__builtin_ia32_addpd512_mask: - case X86::BI__builtin_ia32_addps512_mask: - case X86::BI__builtin_ia32_divpd512_mask: - case X86::BI__builtin_ia32_divps512_mask: - case X86::BI__builtin_ia32_mulpd512_mask: - case X86::BI__builtin_ia32_mulps512_mask: - case X86::BI__builtin_ia32_subpd512_mask: - case X86::BI__builtin_ia32_subps512_mask: case X86::BI__builtin_ia32_addss_round_mask: case X86::BI__builtin_ia32_addsd_round_mask: case X86::BI__builtin_ia32_divss_round_mask: @@ -2092,34 +3216,28 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cvtsd2ss_round_mask: case X86::BI__builtin_ia32_sqrtsd_round_mask: case X86::BI__builtin_ia32_sqrtss_round_mask: + case X86::BI__builtin_ia32_vfmaddsd3_mask: + case X86::BI__builtin_ia32_vfmaddsd3_maskz: + case X86::BI__builtin_ia32_vfmaddsd3_mask3: + case X86::BI__builtin_ia32_vfmaddss3_mask: + case X86::BI__builtin_ia32_vfmaddss3_maskz: + case X86::BI__builtin_ia32_vfmaddss3_mask3: case X86::BI__builtin_ia32_vfmaddpd512_mask: - case X86::BI__builtin_ia32_vfmaddpd512_mask3: case X86::BI__builtin_ia32_vfmaddpd512_maskz: + case X86::BI__builtin_ia32_vfmaddpd512_mask3: + case X86::BI__builtin_ia32_vfmsubpd512_mask3: case X86::BI__builtin_ia32_vfmaddps512_mask: - case X86::BI__builtin_ia32_vfmaddps512_mask3: case X86::BI__builtin_ia32_vfmaddps512_maskz: + case X86::BI__builtin_ia32_vfmaddps512_mask3: + case X86::BI__builtin_ia32_vfmsubps512_mask3: case X86::BI__builtin_ia32_vfmaddsubpd512_mask: - case X86::BI__builtin_ia32_vfmaddsubpd512_mask3: case X86::BI__builtin_ia32_vfmaddsubpd512_maskz: + case X86::BI__builtin_ia32_vfmaddsubpd512_mask3: + case X86::BI__builtin_ia32_vfmsubaddpd512_mask3: case X86::BI__builtin_ia32_vfmaddsubps512_mask: - case X86::BI__builtin_ia32_vfmaddsubps512_mask3: case X86::BI__builtin_ia32_vfmaddsubps512_maskz: - case X86::BI__builtin_ia32_vfmsubpd512_mask3: - case X86::BI__builtin_ia32_vfmsubps512_mask3: - case X86::BI__builtin_ia32_vfmsubaddpd512_mask3: + case X86::BI__builtin_ia32_vfmaddsubps512_mask3: case X86::BI__builtin_ia32_vfmsubaddps512_mask3: - case X86::BI__builtin_ia32_vfnmaddpd512_mask: - case X86::BI__builtin_ia32_vfnmaddps512_mask: - case X86::BI__builtin_ia32_vfnmsubpd512_mask: - case X86::BI__builtin_ia32_vfnmsubpd512_mask3: - case X86::BI__builtin_ia32_vfnmsubps512_mask: - case X86::BI__builtin_ia32_vfnmsubps512_mask3: - case X86::BI__builtin_ia32_vfmaddsd3_mask: - case X86::BI__builtin_ia32_vfmaddsd3_maskz: - case X86::BI__builtin_ia32_vfmaddsd3_mask3: - case X86::BI__builtin_ia32_vfmaddss3_mask: - case X86::BI__builtin_ia32_vfmaddss3_maskz: - case X86::BI__builtin_ia32_vfmaddss3_mask3: ArgNum = 4; HasRC = true; break; @@ -2256,6 +3374,17 @@ bool Sema::CheckX86BuiltinGatherScatterScale(unsigned BuiltinID, << Arg->getSourceRange(); } +static bool isX86_32Builtin(unsigned BuiltinID) { + // These builtins only work on x86-32 targets. + switch (BuiltinID) { + case X86::BI__builtin_ia32_readeflags_u32: + case X86::BI__builtin_ia32_writeeflags_u32: + return true; + } + + return false; +} + bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (BuiltinID == X86::BI__builtin_cpu_supports) return SemaBuiltinCpuSupports(*this, TheCall); @@ -2263,6 +3392,12 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (BuiltinID == X86::BI__builtin_cpu_is) return SemaBuiltinCpuIs(*this, TheCall); + // Check for 32-bit only builtins on a 64-bit target. + const llvm::Triple &TT = Context.getTargetInfo().getTriple(); + if (TT.getArch() != llvm::Triple::x86 && isX86_32Builtin(BuiltinID)) + return Diag(TheCall->getCallee()->getLocStart(), + diag::err_32_bit_builtin_64_bit_tgt); + // If the intrinsic has rounding or SAE make sure its valid. if (CheckX86BuiltinRoundingOrSAE(BuiltinID, TheCall)) return true; @@ -2277,14 +3412,67 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { switch (BuiltinID) { default: return false; + case X86::BI__builtin_ia32_vec_ext_v2si: + case X86::BI__builtin_ia32_vec_ext_v2di: + case X86::BI__builtin_ia32_vextractf128_pd256: + case X86::BI__builtin_ia32_vextractf128_ps256: + case X86::BI__builtin_ia32_vextractf128_si256: + case X86::BI__builtin_ia32_extract128i256: + case X86::BI__builtin_ia32_extractf64x4_mask: + case X86::BI__builtin_ia32_extracti64x4_mask: + case X86::BI__builtin_ia32_extractf32x8_mask: + case X86::BI__builtin_ia32_extracti32x8_mask: + case X86::BI__builtin_ia32_extractf64x2_256_mask: + case X86::BI__builtin_ia32_extracti64x2_256_mask: + case X86::BI__builtin_ia32_extractf32x4_256_mask: + case X86::BI__builtin_ia32_extracti32x4_256_mask: + i = 1; l = 0; u = 1; + break; + case X86::BI__builtin_ia32_vec_set_v2di: + case X86::BI__builtin_ia32_vinsertf128_pd256: + case X86::BI__builtin_ia32_vinsertf128_ps256: + case X86::BI__builtin_ia32_vinsertf128_si256: + case X86::BI__builtin_ia32_insert128i256: + case X86::BI__builtin_ia32_insertf32x8: + case X86::BI__builtin_ia32_inserti32x8: + case X86::BI__builtin_ia32_insertf64x4: + case X86::BI__builtin_ia32_inserti64x4: + case X86::BI__builtin_ia32_insertf64x2_256: + case X86::BI__builtin_ia32_inserti64x2_256: + case X86::BI__builtin_ia32_insertf32x4_256: + case X86::BI__builtin_ia32_inserti32x4_256: + i = 2; l = 0; u = 1; + break; + case X86::BI__builtin_ia32_vpermilpd: + case X86::BI__builtin_ia32_vec_ext_v4hi: + case X86::BI__builtin_ia32_vec_ext_v4si: + case X86::BI__builtin_ia32_vec_ext_v4sf: + case X86::BI__builtin_ia32_vec_ext_v4di: + case X86::BI__builtin_ia32_extractf32x4_mask: + case X86::BI__builtin_ia32_extracti32x4_mask: + case X86::BI__builtin_ia32_extractf64x2_512_mask: + case X86::BI__builtin_ia32_extracti64x2_512_mask: + i = 1; l = 0; u = 3; + break; case X86::BI_mm_prefetch: + case X86::BI__builtin_ia32_vec_ext_v8hi: + case X86::BI__builtin_ia32_vec_ext_v8si: i = 1; l = 0; u = 7; break; case X86::BI__builtin_ia32_sha1rnds4: - case X86::BI__builtin_ia32_shuf_f32x4_256_mask: - case X86::BI__builtin_ia32_shuf_f64x2_256_mask: - case X86::BI__builtin_ia32_shuf_i32x4_256_mask: - case X86::BI__builtin_ia32_shuf_i64x2_256_mask: + case X86::BI__builtin_ia32_blendpd: + case X86::BI__builtin_ia32_shufpd: + case X86::BI__builtin_ia32_vec_set_v4hi: + case X86::BI__builtin_ia32_vec_set_v4si: + case X86::BI__builtin_ia32_vec_set_v4di: + case X86::BI__builtin_ia32_shuf_f32x4_256: + case X86::BI__builtin_ia32_shuf_f64x2_256: + case X86::BI__builtin_ia32_shuf_i32x4_256: + case X86::BI__builtin_ia32_shuf_i64x2_256: + case X86::BI__builtin_ia32_insertf64x2_512: + case X86::BI__builtin_ia32_inserti64x2_512: + case X86::BI__builtin_ia32_insertf32x4: + case X86::BI__builtin_ia32_inserti32x4: i = 2; l = 0; u = 3; break; case X86::BI__builtin_ia32_vpermil2pd: @@ -2325,14 +3513,29 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_vpcomw: case X86::BI__builtin_ia32_vpcomd: case X86::BI__builtin_ia32_vpcomq: + case X86::BI__builtin_ia32_vec_set_v8hi: + case X86::BI__builtin_ia32_vec_set_v8si: i = 2; l = 0; u = 7; break; + case X86::BI__builtin_ia32_vpermilpd256: case X86::BI__builtin_ia32_roundps: case X86::BI__builtin_ia32_roundpd: case X86::BI__builtin_ia32_roundps256: case X86::BI__builtin_ia32_roundpd256: + case X86::BI__builtin_ia32_getmantpd128_mask: + case X86::BI__builtin_ia32_getmantpd256_mask: + case X86::BI__builtin_ia32_getmantps128_mask: + case X86::BI__builtin_ia32_getmantps256_mask: + case X86::BI__builtin_ia32_getmantpd512_mask: + case X86::BI__builtin_ia32_getmantps512_mask: + case X86::BI__builtin_ia32_vec_ext_v16qi: + case X86::BI__builtin_ia32_vec_ext_v16hi: i = 1; l = 0; u = 15; break; + case X86::BI__builtin_ia32_pblendd128: + case X86::BI__builtin_ia32_blendps: + case X86::BI__builtin_ia32_blendpd256: + case X86::BI__builtin_ia32_shufpd256: case X86::BI__builtin_ia32_roundss: case X86::BI__builtin_ia32_roundsd: case X86::BI__builtin_ia32_rangepd128_mask: @@ -2343,8 +3546,13 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_rangeps512_mask: case X86::BI__builtin_ia32_getmantsd_round_mask: case X86::BI__builtin_ia32_getmantss_round_mask: + case X86::BI__builtin_ia32_vec_set_v16qi: + case X86::BI__builtin_ia32_vec_set_v16hi: i = 2; l = 0; u = 15; break; + case X86::BI__builtin_ia32_vec_ext_v32qi: + i = 1; l = 0; u = 31; + break; case X86::BI__builtin_ia32_cmpps: case X86::BI__builtin_ia32_cmpss: case X86::BI__builtin_ia32_cmppd: @@ -2359,15 +3567,26 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cmppd512_mask: case X86::BI__builtin_ia32_cmpsd_mask: case X86::BI__builtin_ia32_cmpss_mask: + case X86::BI__builtin_ia32_vec_set_v32qi: i = 2; l = 0; u = 31; break; - case X86::BI__builtin_ia32_xabort: - i = 0; l = -128; u = 255; - break; - case X86::BI__builtin_ia32_pshufw: - case X86::BI__builtin_ia32_aeskeygenassist128: - i = 1; l = -128; u = 255; - break; + case X86::BI__builtin_ia32_permdf256: + case X86::BI__builtin_ia32_permdi256: + case X86::BI__builtin_ia32_permdf512: + case X86::BI__builtin_ia32_permdi512: + case X86::BI__builtin_ia32_vpermilps: + case X86::BI__builtin_ia32_vpermilps256: + case X86::BI__builtin_ia32_vpermilpd512: + case X86::BI__builtin_ia32_vpermilps512: + case X86::BI__builtin_ia32_pshufd: + case X86::BI__builtin_ia32_pshufd256: + case X86::BI__builtin_ia32_pshufd512: + case X86::BI__builtin_ia32_pshufhw: + case X86::BI__builtin_ia32_pshufhw256: + case X86::BI__builtin_ia32_pshufhw512: + case X86::BI__builtin_ia32_pshuflw: + case X86::BI__builtin_ia32_pshuflw256: + case X86::BI__builtin_ia32_pshuflw512: case X86::BI__builtin_ia32_vcvtps2ph: case X86::BI__builtin_ia32_vcvtps2ph_mask: case X86::BI__builtin_ia32_vcvtps2ph256: @@ -2385,16 +3604,18 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_reduceps128_mask: case X86::BI__builtin_ia32_reduceps256_mask: case X86::BI__builtin_ia32_reduceps512_mask: - case X86::BI__builtin_ia32_prold512_mask: - case X86::BI__builtin_ia32_prolq512_mask: - case X86::BI__builtin_ia32_prold128_mask: - case X86::BI__builtin_ia32_prold256_mask: - case X86::BI__builtin_ia32_prolq128_mask: - case X86::BI__builtin_ia32_prolq256_mask: - case X86::BI__builtin_ia32_prord128_mask: - case X86::BI__builtin_ia32_prord256_mask: - case X86::BI__builtin_ia32_prorq128_mask: - case X86::BI__builtin_ia32_prorq256_mask: + case X86::BI__builtin_ia32_prold512: + case X86::BI__builtin_ia32_prolq512: + case X86::BI__builtin_ia32_prold128: + case X86::BI__builtin_ia32_prold256: + case X86::BI__builtin_ia32_prolq128: + case X86::BI__builtin_ia32_prolq256: + case X86::BI__builtin_ia32_prord512: + case X86::BI__builtin_ia32_prorq512: + case X86::BI__builtin_ia32_prord128: + case X86::BI__builtin_ia32_prord256: + case X86::BI__builtin_ia32_prorq128: + case X86::BI__builtin_ia32_prorq256: case X86::BI__builtin_ia32_fpclasspd128_mask: case X86::BI__builtin_ia32_fpclasspd256_mask: case X86::BI__builtin_ia32_fpclassps128_mask: @@ -2403,41 +3624,62 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_fpclasspd512_mask: case X86::BI__builtin_ia32_fpclasssd_mask: case X86::BI__builtin_ia32_fpclassss_mask: + case X86::BI__builtin_ia32_pslldqi128_byteshift: + case X86::BI__builtin_ia32_pslldqi256_byteshift: + case X86::BI__builtin_ia32_pslldqi512_byteshift: + case X86::BI__builtin_ia32_psrldqi128_byteshift: + case X86::BI__builtin_ia32_psrldqi256_byteshift: + case X86::BI__builtin_ia32_psrldqi512_byteshift: i = 1; l = 0; u = 255; break; - case X86::BI__builtin_ia32_palignr: - case X86::BI__builtin_ia32_insertps128: - case X86::BI__builtin_ia32_dpps: - case X86::BI__builtin_ia32_dppd: - case X86::BI__builtin_ia32_dpps256: - case X86::BI__builtin_ia32_mpsadbw128: - case X86::BI__builtin_ia32_mpsadbw256: - case X86::BI__builtin_ia32_pcmpistrm128: - case X86::BI__builtin_ia32_pcmpistri128: - case X86::BI__builtin_ia32_pcmpistria128: - case X86::BI__builtin_ia32_pcmpistric128: - case X86::BI__builtin_ia32_pcmpistrio128: - case X86::BI__builtin_ia32_pcmpistris128: - case X86::BI__builtin_ia32_pcmpistriz128: - case X86::BI__builtin_ia32_pclmulqdq128: case X86::BI__builtin_ia32_vperm2f128_pd256: case X86::BI__builtin_ia32_vperm2f128_ps256: case X86::BI__builtin_ia32_vperm2f128_si256: case X86::BI__builtin_ia32_permti256: - i = 2; l = -128; u = 255; - break; + case X86::BI__builtin_ia32_pblendw128: + case X86::BI__builtin_ia32_pblendw256: + case X86::BI__builtin_ia32_blendps256: + case X86::BI__builtin_ia32_pblendd256: case X86::BI__builtin_ia32_palignr128: case X86::BI__builtin_ia32_palignr256: - case X86::BI__builtin_ia32_palignr512_mask: + case X86::BI__builtin_ia32_palignr512: + case X86::BI__builtin_ia32_alignq512: + case X86::BI__builtin_ia32_alignd512: + case X86::BI__builtin_ia32_alignd128: + case X86::BI__builtin_ia32_alignd256: + case X86::BI__builtin_ia32_alignq128: + case X86::BI__builtin_ia32_alignq256: case X86::BI__builtin_ia32_vcomisd: case X86::BI__builtin_ia32_vcomiss: - case X86::BI__builtin_ia32_shuf_f32x4_mask: - case X86::BI__builtin_ia32_shuf_f64x2_mask: - case X86::BI__builtin_ia32_shuf_i32x4_mask: - case X86::BI__builtin_ia32_shuf_i64x2_mask: - case X86::BI__builtin_ia32_dbpsadbw128_mask: - case X86::BI__builtin_ia32_dbpsadbw256_mask: - case X86::BI__builtin_ia32_dbpsadbw512_mask: + case X86::BI__builtin_ia32_shuf_f32x4: + case X86::BI__builtin_ia32_shuf_f64x2: + case X86::BI__builtin_ia32_shuf_i32x4: + case X86::BI__builtin_ia32_shuf_i64x2: + case X86::BI__builtin_ia32_shufpd512: + case X86::BI__builtin_ia32_shufps: + case X86::BI__builtin_ia32_shufps256: + case X86::BI__builtin_ia32_shufps512: + case X86::BI__builtin_ia32_dbpsadbw128: + case X86::BI__builtin_ia32_dbpsadbw256: + case X86::BI__builtin_ia32_dbpsadbw512: + case X86::BI__builtin_ia32_vpshldd128: + case X86::BI__builtin_ia32_vpshldd256: + case X86::BI__builtin_ia32_vpshldd512: + case X86::BI__builtin_ia32_vpshldq128: + case X86::BI__builtin_ia32_vpshldq256: + case X86::BI__builtin_ia32_vpshldq512: + case X86::BI__builtin_ia32_vpshldw128: + case X86::BI__builtin_ia32_vpshldw256: + case X86::BI__builtin_ia32_vpshldw512: + case X86::BI__builtin_ia32_vpshrdd128: + case X86::BI__builtin_ia32_vpshrdd256: + case X86::BI__builtin_ia32_vpshrdd512: + case X86::BI__builtin_ia32_vpshrdq128: + case X86::BI__builtin_ia32_vpshrdq256: + case X86::BI__builtin_ia32_vpshrdq512: + case X86::BI__builtin_ia32_vpshrdw128: + case X86::BI__builtin_ia32_vpshrdw256: + case X86::BI__builtin_ia32_vpshrdw512: i = 2; l = 0; u = 255; break; case X86::BI__builtin_ia32_fixupimmpd512_mask: @@ -2480,21 +3722,17 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_scatterpfqps: i = 4; l = 2; u = 3; break; - case X86::BI__builtin_ia32_pcmpestrm128: - case X86::BI__builtin_ia32_pcmpestri128: - case X86::BI__builtin_ia32_pcmpestria128: - case X86::BI__builtin_ia32_pcmpestric128: - case X86::BI__builtin_ia32_pcmpestrio128: - case X86::BI__builtin_ia32_pcmpestris128: - case X86::BI__builtin_ia32_pcmpestriz128: - i = 4; l = -128; u = 255; - break; case X86::BI__builtin_ia32_rndscalesd_round_mask: case X86::BI__builtin_ia32_rndscaless_round_mask: i = 4; l = 0; u = 255; break; } - return SemaBuiltinConstantArgRange(TheCall, i, l, u); + + // Note that we don't force a hard error on the range check here, allowing + // template-generated or macro-generated dead code to potentially have out-of- + // range values. These need to code generate, but don't need to necessarily + // make any sense. We use a warning that defaults to an error. + return SemaBuiltinConstantArgRange(TheCall, i, l, u, /*RangeIsError*/ false); } /// Given a FunctionDecl's FormatAttr, attempts to populate the FomatStringInfo @@ -2522,7 +3760,7 @@ bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, /// Checks if a the given expression evaluates to null. /// -/// \brief Returns true if the value evaluates to null. +/// Returns true if the value evaluates to null. static bool CheckNonNullExpr(Sema &S, const Expr *Expr) { // If the expression has non-null type, it doesn't evaluate to null. if (auto nullability @@ -2566,7 +3804,7 @@ bool Sema::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) { return false; } -/// \brief Diagnose use of %s directive in an NSString which is being passed +/// Diagnose use of %s directive in an NSString which is being passed /// as formatting string to formatting method. static void DiagnoseCStringFormatDirectiveInCFAPI(Sema &S, @@ -2612,7 +3850,7 @@ DiagnoseCStringFormatDirectiveInCFAPI(Sema &S, static bool isNonNullType(ASTContext &ctx, QualType type) { if (auto nullability = type->getNullability(ctx)) return *nullability == NullabilityKind::NonNull; - + return false; } @@ -2636,12 +3874,13 @@ static void CheckNonNullArguments(Sema &S, return; } - for (unsigned Val : NonNull->args()) { - if (Val >= Args.size()) + for (const ParamIdx &Idx : NonNull->args()) { + unsigned IdxAST = Idx.getASTIndex(); + if (IdxAST >= Args.size()) continue; if (NonNullArgs.empty()) NonNullArgs.resize(Args.size()); - NonNullArgs.set(Val); + NonNullArgs.set(IdxAST); } } } @@ -2654,12 +3893,12 @@ static void CheckNonNullArguments(Sema &S, parms = FD->parameters(); else parms = cast<ObjCMethodDecl>(FDecl)->parameters(); - + unsigned ParamIndex = 0; for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end(); I != E; ++I, ++ParamIndex) { const ParmVarDecl *PVD = *I; - if (PVD->hasAttr<NonNullAttr>() || + if (PVD->hasAttr<NonNullAttr>() || isNonNullType(S.Context, PVD->getType())) { if (NonNullArgs.empty()) NonNullArgs.resize(Args.size()); @@ -2681,7 +3920,7 @@ static void CheckNonNullArguments(Sema &S, // Dig out the function prototype, if there is one. Proto = type->getAs<FunctionProtoType>(); - } + } } // Fill in non-null argument information from the nullability @@ -2692,17 +3931,17 @@ static void CheckNonNullArguments(Sema &S, if (isNonNullType(S.Context, paramType)) { if (NonNullArgs.empty()) NonNullArgs.resize(Args.size()); - + NonNullArgs.set(Index); } - + ++Index; } } } // Check for non-null arguments. - for (unsigned ArgIndex = 0, ArgIndexEnd = NonNullArgs.size(); + for (unsigned ArgIndex = 0, ArgIndexEnd = NonNullArgs.size(); ArgIndex != ArgIndexEnd; ++ArgIndex) { if (NonNullArgs[ArgIndex]) CheckNonNullArgument(S, Args[ArgIndex], CallSiteLoc); @@ -2835,7 +4074,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, return false; } -bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac, +bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac, ArrayRef<const Expr *> Args) { VariadicCallType CallType = Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply; @@ -2985,6 +4224,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, Op == AtomicExpr::AO__atomic_exchange_n || Op == AtomicExpr::AO__atomic_compare_exchange_n; bool IsAddSub = false; + bool IsMinMax = false; switch (Op) { case AtomicExpr::AO__c11_atomic_init: @@ -3038,6 +4278,12 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, Form = Arithmetic; break; + case AtomicExpr::AO__atomic_fetch_min: + case AtomicExpr::AO__atomic_fetch_max: + IsMinMax = true; + Form = Arithmetic; + break; + case AtomicExpr::AO__c11_atomic_exchange: case AtomicExpr::AO__opencl_atomic_exchange: case AtomicExpr::AO__atomic_exchange_n: @@ -3120,12 +4366,21 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // For an arithmetic operation, the implied arithmetic must be well-formed. if (Form == Arithmetic) { // gcc does not enforce these rules for GNU atomics, but we do so for sanity. - if (IsAddSub && !ValType->isIntegerType() && !ValType->isPointerType()) { + if (IsAddSub && !ValType->isIntegerType() + && !ValType->isPointerType()) { Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic_int_or_ptr) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } - if (!IsAddSub && !ValType->isIntegerType()) { + if (IsMinMax) { + const BuiltinType *BT = ValType->getAs<BuiltinType>(); + if (!BT || (BT->getKind() != BuiltinType::Int && + BT->getKind() != BuiltinType::UInt)) { + Diag(DRE->getLocStart(), diag::err_atomic_op_needs_int32_or_ptr); + return ExprError(); + } + } + if (!IsAddSub && !IsMinMax && !ValType->isIntegerType()) { Diag(DRE->getLocStart(), diag::err_atomic_op_bitwise_needs_atomic_int) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); @@ -3168,9 +4423,10 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, return ExprError(); } - // atomic_fetch_or takes a pointer to a volatile 'A'. We shouldn't let the - // volatile-ness of the pointee-type inject itself into the result or the - // other operands. Similarly atomic_load can take a pointer to a const 'A'. + // All atomic operations have an overload which takes a pointer to a volatile + // 'A'. We shouldn't let the volatile-ness of the pointee-type inject itself + // into the result or the other operands. Similarly atomic_load takes a + // pointer to a const 'A'. ValType.removeLocalVolatile(); ValType.removeLocalConst(); QualType ResultType = ValType; @@ -3183,16 +4439,27 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // The type of a parameter passed 'by value'. In the GNU atomics, such // arguments are actually passed as pointers. QualType ByValType = ValType; // 'CP' - if (!IsC11 && !IsN) + bool IsPassedByAddress = false; + if (!IsC11 && !IsN) { ByValType = Ptr->getType(); + IsPassedByAddress = true; + } - // The first argument --- the pointer --- has a fixed type; we - // deduce the types of the rest of the arguments accordingly. Walk - // the remaining arguments, converting them to the deduced value type. - for (unsigned i = 1; i != TheCall->getNumArgs(); ++i) { + // The first argument's non-CV pointer type is used to deduce the type of + // subsequent arguments, except for: + // - weak flag (always converted to bool) + // - memory order (always converted to int) + // - scope (always converted to int) + for (unsigned i = 0; i != TheCall->getNumArgs(); ++i) { QualType Ty; if (i < NumVals[Form] + 1) { switch (i) { + case 0: + // The first argument is always a pointer. It has a fixed type. + // It is always dereferenced, a nullptr is undefined. + CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getLocStart()); + // Nothing else to do: we already know all we want about this pointer. + continue; case 1: // The second argument is the non-atomic operand. For arithmetic, this // is always passed by value, and for a compare_exchange it is always @@ -3201,14 +4468,16 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, assert(Form != Load); if (Form == Init || (Form == Arithmetic && ValType->isIntegerType())) Ty = ValType; - else if (Form == Copy || Form == Xchg) + else if (Form == Copy || Form == Xchg) { + if (IsPassedByAddress) + // The value pointer is always dereferenced, a nullptr is undefined. + CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getLocStart()); Ty = ByValType; - else if (Form == Arithmetic) + } else if (Form == Arithmetic) Ty = Context.getPointerDiffType(); else { Expr *ValArg = TheCall->getArg(i); - // Treat this argument as _Nonnull as we want to show a warning if - // NULL is passed into it. + // The value pointer is always dereferenced, a nullptr is undefined. CheckNonNullArgument(*this, ValArg, DRE->getLocStart()); LangAS AS = LangAS::Default; // Keep address space of non-atomic pointer type. @@ -3221,8 +4490,10 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, } break; case 2: - // The third argument to compare_exchange / GNU exchange is a - // (pointer to a) desired value. + // The third argument to compare_exchange / GNU exchange is the desired + // value, either by-value (for the C11 and *_n variant) or as a pointer. + if (IsPassedByAddress) + CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getLocStart()); Ty = ByValType; break; case 3: @@ -3306,7 +4577,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr *AE = new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(), SubExprs, ResultType, Op, TheCall->getRParenLoc()); - + if ((Op == AtomicExpr::AO__c11_atomic_load || Op == AtomicExpr::AO__c11_atomic_store || Op == AtomicExpr::AO__opencl_atomic_load || @@ -3393,6 +4664,12 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { return ExprError(); } + if (ValType.isConstQualified()) { + Diag(DRE->getLocStart(), diag::err_atomic_builtin_cannot_be_const) + << FirstArg->getType() << FirstArg->getSourceRange(); + return ExprError(); + } + switch (ValType.getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: @@ -3467,52 +4744,52 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { bool WarnAboutSemanticsChange = false; switch (BuiltinID) { default: llvm_unreachable("Unknown overloaded atomic builtin!"); - case Builtin::BI__sync_fetch_and_add: + case Builtin::BI__sync_fetch_and_add: case Builtin::BI__sync_fetch_and_add_1: case Builtin::BI__sync_fetch_and_add_2: case Builtin::BI__sync_fetch_and_add_4: case Builtin::BI__sync_fetch_and_add_8: case Builtin::BI__sync_fetch_and_add_16: - BuiltinIndex = 0; + BuiltinIndex = 0; break; - - case Builtin::BI__sync_fetch_and_sub: + + case Builtin::BI__sync_fetch_and_sub: case Builtin::BI__sync_fetch_and_sub_1: case Builtin::BI__sync_fetch_and_sub_2: case Builtin::BI__sync_fetch_and_sub_4: case Builtin::BI__sync_fetch_and_sub_8: case Builtin::BI__sync_fetch_and_sub_16: - BuiltinIndex = 1; + BuiltinIndex = 1; break; - - case Builtin::BI__sync_fetch_and_or: + + case Builtin::BI__sync_fetch_and_or: case Builtin::BI__sync_fetch_and_or_1: case Builtin::BI__sync_fetch_and_or_2: case Builtin::BI__sync_fetch_and_or_4: case Builtin::BI__sync_fetch_and_or_8: case Builtin::BI__sync_fetch_and_or_16: - BuiltinIndex = 2; + BuiltinIndex = 2; break; - - case Builtin::BI__sync_fetch_and_and: + + case Builtin::BI__sync_fetch_and_and: case Builtin::BI__sync_fetch_and_and_1: case Builtin::BI__sync_fetch_and_and_2: case Builtin::BI__sync_fetch_and_and_4: case Builtin::BI__sync_fetch_and_and_8: case Builtin::BI__sync_fetch_and_and_16: - BuiltinIndex = 3; + BuiltinIndex = 3; break; - case Builtin::BI__sync_fetch_and_xor: + case Builtin::BI__sync_fetch_and_xor: case Builtin::BI__sync_fetch_and_xor_1: case Builtin::BI__sync_fetch_and_xor_2: case Builtin::BI__sync_fetch_and_xor_4: case Builtin::BI__sync_fetch_and_xor_8: case Builtin::BI__sync_fetch_and_xor_16: - BuiltinIndex = 4; + BuiltinIndex = 4; break; - case Builtin::BI__sync_fetch_and_nand: + case Builtin::BI__sync_fetch_and_nand: case Builtin::BI__sync_fetch_and_nand_1: case Builtin::BI__sync_fetch_and_nand_2: case Builtin::BI__sync_fetch_and_nand_4: @@ -3522,43 +4799,43 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { WarnAboutSemanticsChange = true; break; - case Builtin::BI__sync_add_and_fetch: + case Builtin::BI__sync_add_and_fetch: case Builtin::BI__sync_add_and_fetch_1: case Builtin::BI__sync_add_and_fetch_2: case Builtin::BI__sync_add_and_fetch_4: case Builtin::BI__sync_add_and_fetch_8: case Builtin::BI__sync_add_and_fetch_16: - BuiltinIndex = 6; + BuiltinIndex = 6; break; - - case Builtin::BI__sync_sub_and_fetch: + + case Builtin::BI__sync_sub_and_fetch: case Builtin::BI__sync_sub_and_fetch_1: case Builtin::BI__sync_sub_and_fetch_2: case Builtin::BI__sync_sub_and_fetch_4: case Builtin::BI__sync_sub_and_fetch_8: case Builtin::BI__sync_sub_and_fetch_16: - BuiltinIndex = 7; + BuiltinIndex = 7; break; - - case Builtin::BI__sync_and_and_fetch: + + case Builtin::BI__sync_and_and_fetch: case Builtin::BI__sync_and_and_fetch_1: case Builtin::BI__sync_and_and_fetch_2: case Builtin::BI__sync_and_and_fetch_4: case Builtin::BI__sync_and_and_fetch_8: case Builtin::BI__sync_and_and_fetch_16: - BuiltinIndex = 8; + BuiltinIndex = 8; break; - - case Builtin::BI__sync_or_and_fetch: + + case Builtin::BI__sync_or_and_fetch: case Builtin::BI__sync_or_and_fetch_1: case Builtin::BI__sync_or_and_fetch_2: case Builtin::BI__sync_or_and_fetch_4: case Builtin::BI__sync_or_and_fetch_8: case Builtin::BI__sync_or_and_fetch_16: - BuiltinIndex = 9; + BuiltinIndex = 9; break; - - case Builtin::BI__sync_xor_and_fetch: + + case Builtin::BI__sync_xor_and_fetch: case Builtin::BI__sync_xor_and_fetch_1: case Builtin::BI__sync_xor_and_fetch_2: case Builtin::BI__sync_xor_and_fetch_4: @@ -3567,7 +4844,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { BuiltinIndex = 10; break; - case Builtin::BI__sync_nand_and_fetch: + case Builtin::BI__sync_nand_and_fetch: case Builtin::BI__sync_nand_and_fetch_1: case Builtin::BI__sync_nand_and_fetch_2: case Builtin::BI__sync_nand_and_fetch_4: @@ -3586,7 +4863,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { BuiltinIndex = 12; NumFixed = 2; break; - + case Builtin::BI__sync_bool_compare_and_swap: case Builtin::BI__sync_bool_compare_and_swap_1: case Builtin::BI__sync_bool_compare_and_swap_2: @@ -3597,16 +4874,16 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { NumFixed = 2; ResultType = Context.BoolTy; break; - - case Builtin::BI__sync_lock_test_and_set: + + case Builtin::BI__sync_lock_test_and_set: case Builtin::BI__sync_lock_test_and_set_1: case Builtin::BI__sync_lock_test_and_set_2: case Builtin::BI__sync_lock_test_and_set_4: case Builtin::BI__sync_lock_test_and_set_8: case Builtin::BI__sync_lock_test_and_set_16: - BuiltinIndex = 14; + BuiltinIndex = 14; break; - + case Builtin::BI__sync_lock_release: case Builtin::BI__sync_lock_release_1: case Builtin::BI__sync_lock_release_2: @@ -3617,14 +4894,14 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { NumFixed = 0; ResultType = Context.VoidTy; break; - - case Builtin::BI__sync_swap: + + case Builtin::BI__sync_swap: case Builtin::BI__sync_swap_1: case Builtin::BI__sync_swap_2: case Builtin::BI__sync_swap_4: case Builtin::BI__sync_swap_8: case Builtin::BI__sync_swap_16: - BuiltinIndex = 16; + BuiltinIndex = 16; break; } @@ -4115,21 +5392,25 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { diag::err_typecheck_call_invalid_unary_fp) << OrigArg->getType() << OrigArg->getSourceRange(); - // If this is an implicit conversion from float -> float or double, remove it. + // If this is an implicit conversion from float -> float, double, or + // long double, remove it. if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(OrigArg)) { // Only remove standard FloatCasts, leaving other casts inplace if (Cast->getCastKind() == CK_FloatingCast) { Expr *CastArg = Cast->getSubExpr(); if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) { - assert((Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) || - Cast->getType()->isSpecificBuiltinType(BuiltinType::Float)) && - "promotion from float to either float or double is the only expected cast here"); + assert( + (Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) || + Cast->getType()->isSpecificBuiltinType(BuiltinType::Float) || + Cast->getType()->isSpecificBuiltinType(BuiltinType::LongDouble)) && + "promotion from float to either float, double, or long double is " + "the only expected cast here"); Cast->setSubExpr(nullptr); TheCall->setArg(NumArgs-1, CastArg); } } } - + return false; } @@ -4506,20 +5787,20 @@ bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, Expr *Arg = TheCall->getArg(ArgNum); DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl()); - + if (Arg->isTypeDependent() || Arg->isValueDependent()) return false; - + if (!Arg->isIntegerConstantExpr(Result, Context)) return Diag(TheCall->getLocStart(), diag::err_constant_integer_arg_type) << FDecl->getDeclName() << Arg->getSourceRange(); - + return false; } /// SemaBuiltinConstantArgRange - Handle a check if argument ArgNum of CallExpr /// TheCall is a constant expression in the range [Low, High]. bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, - int Low, int High) { + int Low, int High, bool RangeIsError) { llvm::APSInt Result; // We can't check the value of a dependent argument. @@ -4531,9 +5812,18 @@ bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) return true; - if (Result.getSExtValue() < Low || Result.getSExtValue() > High) - return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) - << Low << High << Arg->getSourceRange(); + if (Result.getSExtValue() < Low || Result.getSExtValue() > High) { + if (RangeIsError) + return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) + << Result.toString(10) << Low << High << Arg->getSourceRange(); + else + // Defer the warning until we know if the code will be emitted so that + // dead code can ignore this. + DiagRuntimeBehavior(TheCall->getLocStart(), TheCall, + PDiag(diag::warn_argument_invalid_range) + << Result.toString(10) << Low << High + << Arg->getSourceRange()); + } return false; } @@ -4674,7 +5964,7 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { // TODO: This is less than ideal. Overload this to take a value. if (SemaBuiltinConstantArg(TheCall, 1, Result)) return true; - + if (Result != 1) return Diag(TheCall->getLocStart(), diag::err_builtin_longjmp_invalid_val) << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); @@ -4831,11 +6121,13 @@ class FormatStringLiteral { StartToken, StartTokenByteOffset); } - SourceLocation getLocStart() const LLVM_READONLY { + SourceLocation getLocStart() const LLVM_READONLY { return getBeginLoc(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return FExpr->getLocStart().getLocWithOffset(Offset); } - SourceLocation getLocEnd() const LLVM_READONLY { return FExpr->getLocEnd(); } + SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } + SourceLocation getEndLoc() const LLVM_READONLY { return FExpr->getLocEnd(); } }; } // namespace @@ -4941,7 +6233,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, // cannot contain format specifiers and thus are not a security // liability. return SLCT_UncheckedLiteral; - + case Stmt::DeclRefExprClass: { const DeclRefExpr *DR = cast<DeclRefExpr>(E); @@ -5018,18 +6310,22 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, case Stmt::CXXMemberCallExprClass: { const CallExpr *CE = cast<CallExpr>(E); if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) { - if (const FormatArgAttr *FA = ND->getAttr<FormatArgAttr>()) { - unsigned ArgIndex = FA->getFormatIdx(); - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND)) - if (MD->isInstance()) - --ArgIndex; - const Expr *Arg = CE->getArg(ArgIndex - 1); - - return checkFormatStringExpr(S, Arg, Args, - HasVAListArg, format_idx, firstDataArg, - Type, CallType, InFunctionCall, - CheckedVarArgs, UncoveredArg, Offset); - } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { + bool IsFirst = true; + StringLiteralCheckType CommonResult; + for (const auto *FA : ND->specific_attrs<FormatArgAttr>()) { + const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex()); + StringLiteralCheckType Result = checkFormatStringExpr( + S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, + CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset); + if (IsFirst) { + CommonResult = Result; + IsFirst = false; + } + } + if (!IsFirst) + return CommonResult; + + if (const auto *FD = dyn_cast<FunctionDecl>(ND)) { unsigned BuiltinID = FD->getBuiltinID(); if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString || BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) { @@ -5049,8 +6345,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, const auto *ME = cast<ObjCMessageExpr>(E); if (const auto *ND = ME->getMethodDecl()) { if (const auto *FA = ND->getAttr<FormatArgAttr>()) { - unsigned ArgIndex = FA->getFormatIdx(); - const Expr *Arg = ME->getArg(ArgIndex - 1); + const Expr *Arg = ME->getArg(FA->getFormatIdx().getASTIndex()); return checkFormatStringExpr( S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset); @@ -5334,14 +6629,14 @@ protected: void HandlePositionalNonpositionalArgs(SourceLocation Loc, const char *startSpec, unsigned specifierLen); - + SourceRange getFormatStringRange(); CharSourceRange getSpecifierRange(const char *startSpecifier, unsigned specifierLen); SourceLocation getLocationOfByte(const char *x); const Expr *getDataArg(unsigned i) const; - + bool CheckNumArgs(const analyze_format_string::FormatSpecifier &FS, const analyze_format_string::ConversionSpecifier &CS, const char *startSpecifier, unsigned specifierLen, @@ -5655,7 +6950,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag, Loc, IsStringLocation, StringRange, FixIt); } -/// \brief If the format string is not within the funcion call, emit a note +/// If the format string is not within the function call, emit a note /// so that the function call and string are in diagnostic messages. /// /// \param InFunctionCall if true, the format string is within the function @@ -5760,7 +7055,7 @@ public: const char *startSpecifier, unsigned specifierLen); bool checkForCStrMembers(const analyze_printf::ArgType &AT, const Expr *E); - + void HandleEmptyObjCModifierFlag(const char *startFlag, unsigned flagLen) override; @@ -5769,7 +7064,7 @@ public: void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart, const char *flagsEnd, - const char *conversionPosition) + const char *conversionPosition) override; }; @@ -5781,7 +7076,7 @@ bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier( unsigned specifierLen) { const analyze_printf::PrintfConversionSpecifier &CS = FS.getConversionSpecifier(); - + return HandleInvalidConversionSpecifier(FS.getArgIndex(), getLocationOfByte(CS.getStart()), startSpecifier, specifierLen, @@ -6326,11 +7621,11 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, ExprTy = TET->getUnderlyingExpr()->getType(); } - analyze_printf::ArgType::MatchKind match = AT.matchesType(S.Context, ExprTy); - - if (match == analyze_printf::ArgType::Match) { + const analyze_printf::ArgType::MatchKind Match = + AT.matchesType(S.Context, ExprTy); + bool Pedantic = Match == analyze_printf::ArgType::NoMatchPedantic; + if (Match == analyze_printf::ArgType::Match) return true; - } // Look through argument promotions for our error message's reported type. // This includes the integral and floating promotions, but excludes array @@ -6406,6 +7701,12 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, QualType CastTy; std::tie(CastTy, CastTyName) = shouldNotPrintDirectly(S.Context, IntendedTy, E); if (!CastTy.isNull()) { + // %zi/%zu and %td/%tu are OK to use for NSInteger/NSUInteger of type int + // (long in ASTContext). Only complain to pedants. + if ((CastTyName == "NSInteger" || CastTyName == "NSUInteger") && + (AT.isSizeT() || AT.isPtrdiffT()) && + AT.matchesType(S.Context, CastTy)) + Pedantic = true; IntendedTy = CastTy; ShouldNotPrintDirectly = true; } @@ -6413,10 +7714,10 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // We may be able to offer a FixItHint if it is a supported type. PrintfSpecifier fixedFS = FS; - bool success = + bool Success = fixedFS.fixType(IntendedTy, S.getLangOpts(), S.Context, isObjCContext()); - if (success) { + if (Success) { // Get the fix string from the fixed format specifier SmallString<16> buf; llvm::raw_svector_ostream os(buf); @@ -6425,13 +7726,13 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen); if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) { - unsigned diag = diag::warn_format_conversion_argument_type_mismatch; - if (match == analyze_format_string::ArgType::NoMatchPedantic) { - diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; - } + unsigned Diag = + Pedantic + ? diag::warn_format_conversion_argument_type_mismatch_pedantic + : diag::warn_format_conversion_argument_type_mismatch; // In this case, the specifier is wrong and should be changed to match // the argument. - EmitFormatDiagnostic(S.PDiag(diag) + EmitFormatDiagnostic(S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << IntendedTy << IsEnum << E->getSourceRange(), E->getLocStart(), @@ -6452,7 +7753,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, CastFix << ")"; SmallVector<FixItHint,4> Hints; - if (!AT.matchesType(S.Context, IntendedTy) || ShouldNotPrintDirectly) + if (!AT.matchesType(S.Context, IntendedTy) || ShouldNotPrintDirectly) Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str())); if (const CStyleCastExpr *CCast = dyn_cast<CStyleCastExpr>(E)) { @@ -6484,14 +7785,16 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, Name = TypedefTy->getDecl()->getName(); else Name = CastTyName; - EmitFormatDiagnostic(S.PDiag(diag::warn_format_argument_needs_cast) - << Name << IntendedTy << IsEnum - << E->getSourceRange(), + unsigned Diag = Pedantic + ? diag::warn_format_argument_needs_cast_pedantic + : diag::warn_format_argument_needs_cast; + EmitFormatDiagnostic(S.PDiag(Diag) << Name << IntendedTy << IsEnum + << E->getSourceRange(), E->getLocStart(), /*IsStringLocation=*/false, SpecRange, Hints); } else { // In this case, the expression could be printed using a different - // specifier, but we've decided that the specifier is probably correct + // specifier, but we've decided that the specifier is probably correct // and we should cast instead. Just use the normal warning message. EmitFormatDiagnostic( S.PDiag(diag::warn_format_conversion_argument_type_mismatch) @@ -6510,13 +7813,13 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, switch (S.isValidVarArgType(ExprTy)) { case Sema::VAK_Valid: case Sema::VAK_ValidInCXX11: { - unsigned diag = diag::warn_format_conversion_argument_type_mismatch; - if (match == analyze_printf::ArgType::NoMatchPedantic) { - diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; - } + unsigned Diag = + Pedantic + ? diag::warn_format_conversion_argument_type_mismatch_pedantic + : diag::warn_format_conversion_argument_type_mismatch; EmitFormatDiagnostic( - S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy + S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy << IsEnum << CSR << E->getSourceRange(), E->getLocStart(), /*IsStringLocation*/ false, CSR); break; @@ -6566,7 +7869,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, //===--- CHECK: Scanf format string checking ------------------------------===// -namespace { +namespace { class CheckScanfHandler : public CheckFormatHandler { public: @@ -6586,7 +7889,7 @@ public: bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) override; - + bool HandleInvalidScanfConversionSpecifier( const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, @@ -6622,7 +7925,7 @@ bool CheckScanfHandler::HandleScanfSpecifier( const char *startSpecifier, unsigned specifierLen) { using namespace analyze_scanf; - using namespace analyze_format_string; + using namespace analyze_format_string; const ScanfConversionSpecifier &CS = FS.getConversionSpecifier(); @@ -6639,7 +7942,7 @@ bool CheckScanfHandler::HandleScanfSpecifier( return false; } } - + // Check if the field with is non-zero. const OptionalAmount &Amt = FS.getFieldWidth(); if (Amt.getHowSpecified() == OptionalAmount::Constant) { @@ -6699,29 +8002,28 @@ bool CheckScanfHandler::HandleScanfSpecifier( return true; } - analyze_format_string::ArgType::MatchKind match = + analyze_format_string::ArgType::MatchKind Match = AT.matchesType(S.Context, Ex->getType()); - if (match == analyze_format_string::ArgType::Match) { + bool Pedantic = Match == analyze_format_string::ArgType::NoMatchPedantic; + if (Match == analyze_format_string::ArgType::Match) return true; - } ScanfSpecifier fixedFS = FS; - bool success = fixedFS.fixType(Ex->getType(), Ex->IgnoreImpCasts()->getType(), + bool Success = fixedFS.fixType(Ex->getType(), Ex->IgnoreImpCasts()->getType(), S.getLangOpts(), S.Context); - unsigned diag = diag::warn_format_conversion_argument_type_mismatch; - if (match == analyze_format_string::ArgType::NoMatchPedantic) { - diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; - } + unsigned Diag = + Pedantic ? diag::warn_format_conversion_argument_type_mismatch_pedantic + : diag::warn_format_conversion_argument_type_mismatch; - if (success) { + if (Success) { // Get the fix string from the fixed format specifier. SmallString<128> buf; llvm::raw_svector_ostream os(buf); fixedFS.toString(os); EmitFormatDiagnostic( - S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context) + S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << Ex->getType() << false << Ex->getSourceRange(), Ex->getLocStart(), /*IsStringLocation*/ false, @@ -6729,7 +8031,7 @@ bool CheckScanfHandler::HandleScanfSpecifier( FixItHint::CreateReplacement( getSpecifierRange(startSpecifier, specifierLen), os.str())); } else { - EmitFormatDiagnostic(S.PDiag(diag) + EmitFormatDiagnostic(S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << Ex->getType() << false << Ex->getSourceRange(), Ex->getLocStart(), @@ -7283,7 +8585,7 @@ void Sema::CheckMaxUnsignedZero(const CallExpr *Call, //===--- CHECK: Standard memory functions ---------------------------------===// -/// \brief Takes the expression passed to the size_t parameter of functions +/// Takes the expression passed to the size_t parameter of functions /// such as memcmp, strncat, etc and warns if it's a comparison. /// /// This is to catch typos like `if (memcmp(&a, &b, sizeof(a) > 0))`. @@ -7314,7 +8616,7 @@ static bool CheckMemorySizeofForComparison(Sema &S, const Expr *E, return true; } -/// \brief Determine whether the given type is or contains a dynamic class type +/// Determine whether the given type is or contains a dynamic class type /// (e.g., whether it has a vtable). static const CXXRecordDecl *getContainedDynamicClass(QualType T, bool &IsContained) { @@ -7345,28 +8647,205 @@ static const CXXRecordDecl *getContainedDynamicClass(QualType T, return nullptr; } -/// \brief If E is a sizeof expression, returns its argument expression, +static const UnaryExprOrTypeTraitExpr *getAsSizeOfExpr(const Expr *E) { + if (const auto *Unary = dyn_cast<UnaryExprOrTypeTraitExpr>(E)) + if (Unary->getKind() == UETT_SizeOf) + return Unary; + return nullptr; +} + +/// If E is a sizeof expression, returns its argument expression, /// otherwise returns NULL. static const Expr *getSizeOfExprArg(const Expr *E) { - if (const UnaryExprOrTypeTraitExpr *SizeOf = - dyn_cast<UnaryExprOrTypeTraitExpr>(E)) - if (SizeOf->getKind() == UETT_SizeOf && !SizeOf->isArgumentType()) + if (const UnaryExprOrTypeTraitExpr *SizeOf = getAsSizeOfExpr(E)) + if (!SizeOf->isArgumentType()) return SizeOf->getArgumentExpr()->IgnoreParenImpCasts(); - return nullptr; } -/// \brief If E is a sizeof expression, returns its argument type. +/// If E is a sizeof expression, returns its argument type. static QualType getSizeOfArgType(const Expr *E) { - if (const UnaryExprOrTypeTraitExpr *SizeOf = - dyn_cast<UnaryExprOrTypeTraitExpr>(E)) - if (SizeOf->getKind() == UETT_SizeOf) - return SizeOf->getTypeOfArgument(); - + if (const UnaryExprOrTypeTraitExpr *SizeOf = getAsSizeOfExpr(E)) + return SizeOf->getTypeOfArgument(); return QualType(); } -/// \brief Check for dangerous or invalid arguments to memset(). +namespace { + +struct SearchNonTrivialToInitializeField + : DefaultInitializedTypeVisitor<SearchNonTrivialToInitializeField> { + using Super = + DefaultInitializedTypeVisitor<SearchNonTrivialToInitializeField>; + + SearchNonTrivialToInitializeField(const Expr *E, Sema &S) : E(E), S(S) {} + + void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT, + SourceLocation SL) { + if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) { + asDerived().visitArray(PDIK, AT, SL); + return; + } + + Super::visitWithKind(PDIK, FT, SL); + } + + void visitARCStrong(QualType FT, SourceLocation SL) { + S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1); + } + void visitARCWeak(QualType FT, SourceLocation SL) { + S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1); + } + void visitStruct(QualType FT, SourceLocation SL) { + for (const FieldDecl *FD : FT->castAs<RecordType>()->getDecl()->fields()) + visit(FD->getType(), FD->getLocation()); + } + void visitArray(QualType::PrimitiveDefaultInitializeKind PDIK, + const ArrayType *AT, SourceLocation SL) { + visit(getContext().getBaseElementType(AT), SL); + } + void visitTrivial(QualType FT, SourceLocation SL) {} + + static void diag(QualType RT, const Expr *E, Sema &S) { + SearchNonTrivialToInitializeField(E, S).visitStruct(RT, SourceLocation()); + } + + ASTContext &getContext() { return S.getASTContext(); } + + const Expr *E; + Sema &S; +}; + +struct SearchNonTrivialToCopyField + : CopiedTypeVisitor<SearchNonTrivialToCopyField, false> { + using Super = CopiedTypeVisitor<SearchNonTrivialToCopyField, false>; + + SearchNonTrivialToCopyField(const Expr *E, Sema &S) : E(E), S(S) {} + + void visitWithKind(QualType::PrimitiveCopyKind PCK, QualType FT, + SourceLocation SL) { + if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) { + asDerived().visitArray(PCK, AT, SL); + return; + } + + Super::visitWithKind(PCK, FT, SL); + } + + void visitARCStrong(QualType FT, SourceLocation SL) { + S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0); + } + void visitARCWeak(QualType FT, SourceLocation SL) { + S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0); + } + void visitStruct(QualType FT, SourceLocation SL) { + for (const FieldDecl *FD : FT->castAs<RecordType>()->getDecl()->fields()) + visit(FD->getType(), FD->getLocation()); + } + void visitArray(QualType::PrimitiveCopyKind PCK, const ArrayType *AT, + SourceLocation SL) { + visit(getContext().getBaseElementType(AT), SL); + } + void preVisit(QualType::PrimitiveCopyKind PCK, QualType FT, + SourceLocation SL) {} + void visitTrivial(QualType FT, SourceLocation SL) {} + void visitVolatileTrivial(QualType FT, SourceLocation SL) {} + + static void diag(QualType RT, const Expr *E, Sema &S) { + SearchNonTrivialToCopyField(E, S).visitStruct(RT, SourceLocation()); + } + + ASTContext &getContext() { return S.getASTContext(); } + + const Expr *E; + Sema &S; +}; + +} + +/// Detect if \c SizeofExpr is likely to calculate the sizeof an object. +static bool doesExprLikelyComputeSize(const Expr *SizeofExpr) { + SizeofExpr = SizeofExpr->IgnoreParenImpCasts(); + + if (const auto *BO = dyn_cast<BinaryOperator>(SizeofExpr)) { + if (BO->getOpcode() != BO_Mul && BO->getOpcode() != BO_Add) + return false; + + return doesExprLikelyComputeSize(BO->getLHS()) || + doesExprLikelyComputeSize(BO->getRHS()); + } + + return getAsSizeOfExpr(SizeofExpr) != nullptr; +} + +/// Check if the ArgLoc originated from a macro passed to the call at CallLoc. +/// +/// \code +/// #define MACRO 0 +/// foo(MACRO); +/// foo(0); +/// \endcode +/// +/// This should return true for the first call to foo, but not for the second +/// (regardless of whether foo is a macro or function). +static bool isArgumentExpandedFromMacro(SourceManager &SM, + SourceLocation CallLoc, + SourceLocation ArgLoc) { + if (!CallLoc.isMacroID()) + return SM.getFileID(CallLoc) != SM.getFileID(ArgLoc); + + return SM.getFileID(SM.getImmediateMacroCallerLoc(CallLoc)) != + SM.getFileID(SM.getImmediateMacroCallerLoc(ArgLoc)); +} + +/// Diagnose cases like 'memset(buf, sizeof(buf), 0)', which should have the +/// last two arguments transposed. +static void CheckMemaccessSize(Sema &S, unsigned BId, const CallExpr *Call) { + if (BId != Builtin::BImemset && BId != Builtin::BIbzero) + return; + + const Expr *SizeArg = + Call->getArg(BId == Builtin::BImemset ? 2 : 1)->IgnoreImpCasts(); + + auto isLiteralZero = [](const Expr *E) { + return isa<IntegerLiteral>(E) && cast<IntegerLiteral>(E)->getValue() == 0; + }; + + // If we're memsetting or bzeroing 0 bytes, then this is likely an error. + SourceLocation CallLoc = Call->getRParenLoc(); + SourceManager &SM = S.getSourceManager(); + if (isLiteralZero(SizeArg) && + !isArgumentExpandedFromMacro(SM, CallLoc, SizeArg->getExprLoc())) { + + SourceLocation DiagLoc = SizeArg->getExprLoc(); + + // Some platforms #define bzero to __builtin_memset. See if this is the + // case, and if so, emit a better diagnostic. + if (BId == Builtin::BIbzero || + (CallLoc.isMacroID() && Lexer::getImmediateMacroName( + CallLoc, SM, S.getLangOpts()) == "bzero")) { + S.Diag(DiagLoc, diag::warn_suspicious_bzero_size); + S.Diag(DiagLoc, diag::note_suspicious_bzero_size_silence); + } else if (!isLiteralZero(Call->getArg(1)->IgnoreImpCasts())) { + S.Diag(DiagLoc, diag::warn_suspicious_sizeof_memset) << 0; + S.Diag(DiagLoc, diag::note_suspicious_sizeof_memset_silence) << 0; + } + return; + } + + // If the second argument to a memset is a sizeof expression and the third + // isn't, this is also likely an error. This should catch + // 'memset(buf, sizeof(buf), 0xff)'. + if (BId == Builtin::BImemset && + doesExprLikelyComputeSize(Call->getArg(1)) && + !doesExprLikelyComputeSize(Call->getArg(2))) { + SourceLocation DiagLoc = Call->getArg(1)->getExprLoc(); + S.Diag(DiagLoc, diag::warn_suspicious_sizeof_memset) << 1; + S.Diag(DiagLoc, diag::note_suspicious_sizeof_memset_silence) << 1; + return; + } +} + +/// Check for dangerous or invalid arguments to memset(). /// /// This issues warnings on known problematic, dangerous or unspecified /// arguments to the standard 'memset', 'memcpy', 'memmove', and 'memcmp' @@ -7395,6 +8874,9 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, Call->getLocStart(), Call->getRParenLoc())) return; + // Catch cases like 'memset(buf, sizeof(buf), 0)'. + CheckMemaccessSize(*this, BId, Call); + // We have special checking when the length is a sizeof expression. QualType SizeOfArgTy = getSizeOfArgType(LenExpr); const Expr *SizeOfArg = getSizeOfExprArg(LenExpr); @@ -7517,7 +8999,7 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, else if (BId == Builtin::BImemcmp) OperationType = 3; } - + DiagRuntimeBehavior( Dest->getExprLoc(), Dest, PDiag(diag::warn_dyn_class_memaccess) @@ -7531,7 +9013,23 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, PDiag(diag::warn_arc_object_memaccess) << ArgIdx << FnName << PointeeTy << Call->getCallee()->getSourceRange()); - else + else if (const auto *RT = PointeeTy->getAs<RecordType>()) { + if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) && + RT->getDecl()->isNonTrivialToPrimitiveDefaultInitialize()) { + DiagRuntimeBehavior(Dest->getExprLoc(), Dest, + PDiag(diag::warn_cstruct_memaccess) + << ArgIdx << FnName << PointeeTy << 0); + SearchNonTrivialToInitializeField::diag(PointeeTy, Dest, *this); + } else if ((BId == Builtin::BImemcpy || BId == Builtin::BImemmove) && + RT->getDecl()->isNonTrivialToPrimitiveCopy()) { + DiagRuntimeBehavior(Dest->getExprLoc(), Dest, + PDiag(diag::warn_cstruct_memaccess) + << ArgIdx << FnName << PointeeTy << 1); + SearchNonTrivialToCopyField::diag(PointeeTy, Dest, *this); + } else { + continue; + } + } else continue; DiagRuntimeBehavior( @@ -7555,7 +9053,7 @@ static const Expr *ignoreLiteralAdditions(const Expr *Ex, ASTContext &Ctx) { const Expr *RHS = BO->getRHS()->IgnoreParenCasts(); const Expr *LHS = BO->getLHS()->IgnoreParenCasts(); - + if (isa<IntegerLiteral>(RHS)) Ex = LHS; else if (isa<IntegerLiteral>(LHS)) @@ -7597,7 +9095,7 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call, if (CheckMemorySizeofForComparison(*this, SizeArg, FnName, Call->getLocStart(), Call->getRParenLoc())) return; - + // Look for 'strlcpy(dst, x, sizeof(x))' if (const Expr *Ex = getSizeOfExprArg(SizeArg)) CompareWithSrc = Ex; @@ -7620,16 +9118,16 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call, const DeclRefExpr *SrcArgDRE = dyn_cast<DeclRefExpr>(SrcArg); if (!SrcArgDRE) return; - + const DeclRefExpr *CompareWithSrcDRE = dyn_cast<DeclRefExpr>(CompareWithSrc); - if (!CompareWithSrcDRE || + if (!CompareWithSrcDRE || SrcArgDRE->getDecl() != CompareWithSrcDRE->getDecl()) return; - + const Expr *OriginalSizeArg = Call->getArg(2); Diag(CompareWithSrcDRE->getLocStart(), diag::warn_strlcpycat_wrong_size) << OriginalSizeArg->getSourceRange() << FnName; - + // Output a FIXIT hint if the destination is an array (rather than a // pointer to an array). This could be enhanced to handle some // pointers if we know the actual size, like if DstArg is 'array+2' @@ -7643,7 +9141,7 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call, OS << "sizeof("; DstArg->printPretty(OS, nullptr, getPrintingPolicy()); OS << ")"; - + Diag(OriginalSizeArg->getLocStart(), diag::note_strlcpycat_wrong_size) << FixItHint::CreateReplacement(OriginalSizeArg->getSourceRange(), OS.str()); @@ -7752,421 +9250,12 @@ void Sema::CheckStrncatArguments(const CallExpr *CE, << FixItHint::CreateReplacement(SR, OS.str()); } -//===--- CHECK: Return Address of Stack Variable --------------------------===// - -static const Expr *EvalVal(const Expr *E, - SmallVectorImpl<const DeclRefExpr *> &refVars, - const Decl *ParentDecl); -static const Expr *EvalAddr(const Expr *E, - SmallVectorImpl<const DeclRefExpr *> &refVars, - const Decl *ParentDecl); - -/// CheckReturnStackAddr - Check if a return statement returns the address -/// of a stack variable. -static void -CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, - SourceLocation ReturnLoc) { - const Expr *stackE = nullptr; - SmallVector<const DeclRefExpr *, 8> refVars; - - // Perform checking for returned stack addresses, local blocks, - // label addresses or references to temporaries. - if (lhsType->isPointerType() || - (!S.getLangOpts().ObjCAutoRefCount && lhsType->isBlockPointerType())) { - stackE = EvalAddr(RetValExp, refVars, /*ParentDecl=*/nullptr); - } else if (lhsType->isReferenceType()) { - stackE = EvalVal(RetValExp, refVars, /*ParentDecl=*/nullptr); - } - - if (!stackE) - return; // Nothing suspicious was found. - - // Parameters are initialized in the calling scope, so taking the address - // of a parameter reference doesn't need a warning. - for (auto *DRE : refVars) - if (isa<ParmVarDecl>(DRE->getDecl())) - return; - - SourceLocation diagLoc; - SourceRange diagRange; - if (refVars.empty()) { - diagLoc = stackE->getLocStart(); - diagRange = stackE->getSourceRange(); - } else { - // We followed through a reference variable. 'stackE' contains the - // problematic expression but we will warn at the return statement pointing - // at the reference variable. We will later display the "trail" of - // reference variables using notes. - diagLoc = refVars[0]->getLocStart(); - diagRange = refVars[0]->getSourceRange(); - } - - if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(stackE)) { - // address of local var - S.Diag(diagLoc, diag::warn_ret_stack_addr_ref) << lhsType->isReferenceType() - << DR->getDecl()->getDeclName() << diagRange; - } else if (isa<BlockExpr>(stackE)) { // local block. - S.Diag(diagLoc, diag::err_ret_local_block) << diagRange; - } else if (isa<AddrLabelExpr>(stackE)) { // address of label. - S.Diag(diagLoc, diag::warn_ret_addr_label) << diagRange; - } else { // local temporary. - // If there is an LValue->RValue conversion, then the value of the - // reference type is used, not the reference. - if (auto *ICE = dyn_cast<ImplicitCastExpr>(RetValExp)) { - if (ICE->getCastKind() == CK_LValueToRValue) { - return; - } - } - S.Diag(diagLoc, diag::warn_ret_local_temp_addr_ref) - << lhsType->isReferenceType() << diagRange; - } - - // Display the "trail" of reference variables that we followed until we - // found the problematic expression using notes. - for (unsigned i = 0, e = refVars.size(); i != e; ++i) { - const VarDecl *VD = cast<VarDecl>(refVars[i]->getDecl()); - // If this var binds to another reference var, show the range of the next - // var, otherwise the var binds to the problematic expression, in which case - // show the range of the expression. - SourceRange range = (i < e - 1) ? refVars[i + 1]->getSourceRange() - : stackE->getSourceRange(); - S.Diag(VD->getLocation(), diag::note_ref_var_local_bind) - << VD->getDeclName() << range; - } -} - -/// EvalAddr - EvalAddr and EvalVal are mutually recursive functions that -/// check if the expression in a return statement evaluates to an address -/// to a location on the stack, a local block, an address of a label, or a -/// reference to local temporary. The recursion is used to traverse the -/// AST of the return expression, with recursion backtracking when we -/// encounter a subexpression that (1) clearly does not lead to one of the -/// above problematic expressions (2) is something we cannot determine leads to -/// a problematic expression based on such local checking. -/// -/// Both EvalAddr and EvalVal follow through reference variables to evaluate -/// the expression that they point to. Such variables are added to the -/// 'refVars' vector so that we know what the reference variable "trail" was. -/// -/// EvalAddr processes expressions that are pointers that are used as -/// references (and not L-values). EvalVal handles all other values. -/// At the base case of the recursion is a check for the above problematic -/// expressions. -/// -/// This implementation handles: -/// -/// * pointer-to-pointer casts -/// * implicit conversions from array references to pointers -/// * taking the address of fields -/// * arbitrary interplay between "&" and "*" operators -/// * pointer arithmetic from an address of a stack variable -/// * taking the address of an array element where the array is on the stack -static const Expr *EvalAddr(const Expr *E, - SmallVectorImpl<const DeclRefExpr *> &refVars, - const Decl *ParentDecl) { - if (E->isTypeDependent()) - return nullptr; - - // We should only be called for evaluating pointer expressions. - assert((E->getType()->isAnyPointerType() || - E->getType()->isBlockPointerType() || - E->getType()->isObjCQualifiedIdType()) && - "EvalAddr only works on pointers"); - - E = E->IgnoreParens(); - - // Our "symbolic interpreter" is just a dispatch off the currently - // viewed AST node. We then recursively traverse the AST by calling - // EvalAddr and EvalVal appropriately. - switch (E->getStmtClass()) { - case Stmt::DeclRefExprClass: { - const DeclRefExpr *DR = cast<DeclRefExpr>(E); - - // If we leave the immediate function, the lifetime isn't about to end. - if (DR->refersToEnclosingVariableOrCapture()) - return nullptr; - - if (const VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) - // If this is a reference variable, follow through to the expression that - // it points to. - if (V->hasLocalStorage() && - V->getType()->isReferenceType() && V->hasInit()) { - // Add the reference variable to the "trail". - refVars.push_back(DR); - return EvalAddr(V->getInit(), refVars, ParentDecl); - } - - return nullptr; - } - - case Stmt::UnaryOperatorClass: { - // The only unary operator that make sense to handle here - // is AddrOf. All others don't make sense as pointers. - const UnaryOperator *U = cast<UnaryOperator>(E); - - if (U->getOpcode() == UO_AddrOf) - return EvalVal(U->getSubExpr(), refVars, ParentDecl); - return nullptr; - } - - case Stmt::BinaryOperatorClass: { - // Handle pointer arithmetic. All other binary operators are not valid - // in this context. - const BinaryOperator *B = cast<BinaryOperator>(E); - BinaryOperatorKind op = B->getOpcode(); - - if (op != BO_Add && op != BO_Sub) - return nullptr; - - const Expr *Base = B->getLHS(); - - // Determine which argument is the real pointer base. It could be - // the RHS argument instead of the LHS. - if (!Base->getType()->isPointerType()) - Base = B->getRHS(); - - assert(Base->getType()->isPointerType()); - return EvalAddr(Base, refVars, ParentDecl); - } - - // For conditional operators we need to see if either the LHS or RHS are - // valid DeclRefExpr*s. If one of them is valid, we return it. - case Stmt::ConditionalOperatorClass: { - const ConditionalOperator *C = cast<ConditionalOperator>(E); - - // Handle the GNU extension for missing LHS. - // FIXME: That isn't a ConditionalOperator, so doesn't get here. - if (const Expr *LHSExpr = C->getLHS()) { - // In C++, we can have a throw-expression, which has 'void' type. - if (!LHSExpr->getType()->isVoidType()) - if (const Expr *LHS = EvalAddr(LHSExpr, refVars, ParentDecl)) - return LHS; - } - - // In C++, we can have a throw-expression, which has 'void' type. - if (C->getRHS()->getType()->isVoidType()) - return nullptr; - - return EvalAddr(C->getRHS(), refVars, ParentDecl); - } - - case Stmt::BlockExprClass: - if (cast<BlockExpr>(E)->getBlockDecl()->hasCaptures()) - return E; // local block. - return nullptr; - - case Stmt::AddrLabelExprClass: - return E; // address of label. - - case Stmt::ExprWithCleanupsClass: - return EvalAddr(cast<ExprWithCleanups>(E)->getSubExpr(), refVars, - ParentDecl); - - // For casts, we need to handle conversions from arrays to - // pointer values, and pointer-to-pointer conversions. - case Stmt::ImplicitCastExprClass: - case Stmt::CStyleCastExprClass: - case Stmt::CXXFunctionalCastExprClass: - case Stmt::ObjCBridgedCastExprClass: - case Stmt::CXXStaticCastExprClass: - case Stmt::CXXDynamicCastExprClass: - case Stmt::CXXConstCastExprClass: - case Stmt::CXXReinterpretCastExprClass: { - const Expr* SubExpr = cast<CastExpr>(E)->getSubExpr(); - switch (cast<CastExpr>(E)->getCastKind()) { - case CK_LValueToRValue: - case CK_NoOp: - case CK_BaseToDerived: - case CK_DerivedToBase: - case CK_UncheckedDerivedToBase: - case CK_Dynamic: - case CK_CPointerToObjCPointerCast: - case CK_BlockPointerToObjCPointerCast: - case CK_AnyPointerToBlockPointerCast: - return EvalAddr(SubExpr, refVars, ParentDecl); - - case CK_ArrayToPointerDecay: - return EvalVal(SubExpr, refVars, ParentDecl); - - case CK_BitCast: - if (SubExpr->getType()->isAnyPointerType() || - SubExpr->getType()->isBlockPointerType() || - SubExpr->getType()->isObjCQualifiedIdType()) - return EvalAddr(SubExpr, refVars, ParentDecl); - else - return nullptr; - - default: - return nullptr; - } - } - - case Stmt::MaterializeTemporaryExprClass: - if (const Expr *Result = - EvalAddr(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(), - refVars, ParentDecl)) - return Result; - return E; - - // Everything else: we simply don't reason about them. - default: - return nullptr; - } -} - -/// EvalVal - This function is complements EvalAddr in the mutual recursion. -/// See the comments for EvalAddr for more details. -static const Expr *EvalVal(const Expr *E, - SmallVectorImpl<const DeclRefExpr *> &refVars, - const Decl *ParentDecl) { - do { - // We should only be called for evaluating non-pointer expressions, or - // expressions with a pointer type that are not used as references but - // instead - // are l-values (e.g., DeclRefExpr with a pointer type). - - // Our "symbolic interpreter" is just a dispatch off the currently - // viewed AST node. We then recursively traverse the AST by calling - // EvalAddr and EvalVal appropriately. - - E = E->IgnoreParens(); - switch (E->getStmtClass()) { - case Stmt::ImplicitCastExprClass: { - const ImplicitCastExpr *IE = cast<ImplicitCastExpr>(E); - if (IE->getValueKind() == VK_LValue) { - E = IE->getSubExpr(); - continue; - } - return nullptr; - } - - case Stmt::ExprWithCleanupsClass: - return EvalVal(cast<ExprWithCleanups>(E)->getSubExpr(), refVars, - ParentDecl); - - case Stmt::DeclRefExprClass: { - // When we hit a DeclRefExpr we are looking at code that refers to a - // variable's name. If it's not a reference variable we check if it has - // local storage within the function, and if so, return the expression. - const DeclRefExpr *DR = cast<DeclRefExpr>(E); - - // If we leave the immediate function, the lifetime isn't about to end. - if (DR->refersToEnclosingVariableOrCapture()) - return nullptr; - - if (const VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) { - // Check if it refers to itself, e.g. "int& i = i;". - if (V == ParentDecl) - return DR; - - if (V->hasLocalStorage()) { - if (!V->getType()->isReferenceType()) - return DR; - - // Reference variable, follow through to the expression that - // it points to. - if (V->hasInit()) { - // Add the reference variable to the "trail". - refVars.push_back(DR); - return EvalVal(V->getInit(), refVars, V); - } - } - } - - return nullptr; - } - - case Stmt::UnaryOperatorClass: { - // The only unary operator that make sense to handle here - // is Deref. All others don't resolve to a "name." This includes - // handling all sorts of rvalues passed to a unary operator. - const UnaryOperator *U = cast<UnaryOperator>(E); - - if (U->getOpcode() == UO_Deref) - return EvalAddr(U->getSubExpr(), refVars, ParentDecl); - - return nullptr; - } - - case Stmt::ArraySubscriptExprClass: { - // Array subscripts are potential references to data on the stack. We - // retrieve the DeclRefExpr* for the array variable if it indeed - // has local storage. - const auto *ASE = cast<ArraySubscriptExpr>(E); - if (ASE->isTypeDependent()) - return nullptr; - return EvalAddr(ASE->getBase(), refVars, ParentDecl); - } - - case Stmt::OMPArraySectionExprClass: { - return EvalAddr(cast<OMPArraySectionExpr>(E)->getBase(), refVars, - ParentDecl); - } - - case Stmt::ConditionalOperatorClass: { - // For conditional operators we need to see if either the LHS or RHS are - // non-NULL Expr's. If one is non-NULL, we return it. - const ConditionalOperator *C = cast<ConditionalOperator>(E); - - // Handle the GNU extension for missing LHS. - if (const Expr *LHSExpr = C->getLHS()) { - // In C++, we can have a throw-expression, which has 'void' type. - if (!LHSExpr->getType()->isVoidType()) - if (const Expr *LHS = EvalVal(LHSExpr, refVars, ParentDecl)) - return LHS; - } - - // In C++, we can have a throw-expression, which has 'void' type. - if (C->getRHS()->getType()->isVoidType()) - return nullptr; - - return EvalVal(C->getRHS(), refVars, ParentDecl); - } - - // Accesses to members are potential references to data on the stack. - case Stmt::MemberExprClass: { - const MemberExpr *M = cast<MemberExpr>(E); - - // Check for indirect access. We only want direct field accesses. - if (M->isArrow()) - return nullptr; - - // Check whether the member type is itself a reference, in which case - // we're not going to refer to the member, but to what the member refers - // to. - if (M->getMemberDecl()->getType()->isReferenceType()) - return nullptr; - - return EvalVal(M->getBase(), refVars, ParentDecl); - } - - case Stmt::MaterializeTemporaryExprClass: - if (const Expr *Result = - EvalVal(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(), - refVars, ParentDecl)) - return Result; - return E; - - default: - // Check that we don't return or take the address of a reference to a - // temporary. This is only useful in C++. - if (!E->isTypeDependent() && E->isRValue()) - return E; - - // Everything else: we simply don't reason about them. - return nullptr; - } - } while (true); -} - void Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc, bool isObjCMethod, const AttrVec *Attrs, const FunctionDecl *FD) { - CheckReturnStackAddr(*this, RetValExp, lhsType, ReturnLoc); - // Check if the return value is null but should not be. if (((Attrs && hasSpecificAttr<ReturnsNonNullAttr>(*Attrs)) || (!isObjCMethod && isNonNullType(Context, lhsType))) && @@ -8184,7 +9273,7 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, if (Op == OO_New || Op == OO_Array_New) { const FunctionProtoType *Proto = FD->getType()->castAs<FunctionProtoType>(); - if (!Proto->isNothrow(Context, /*ResultIfDependent*/true) && + if (!Proto->isNothrow(/*ResultIfDependent*/true) && CheckNonNullExpr(*this, RetValExp)) Diag(ReturnLoc, diag::warn_operator_new_returns_null) << FD << getLangOpts().CPlusPlus11; @@ -8933,7 +10022,7 @@ static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); } -/// \brief Implements -Wsign-compare. +/// Implements -Wsign-compare. /// /// \param E the binary operator to check for warnings static void AnalyzeComparison(Sema &S, BinaryOperator *E) { @@ -9200,7 +10289,7 @@ static void AnalyzeAssignment(Sema &S, BinaryOperator *E) { } /// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. -static void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, +static void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, SourceLocation CContext, unsigned diag, bool pruneControlFlow = false) { if (pruneControlFlow) { @@ -9221,6 +10310,32 @@ static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, pruneControlFlow); } +/// Analyze the given compound assignment for the possible losing of +/// floating-point precision. +static void AnalyzeCompoundAssignment(Sema &S, BinaryOperator *E) { + assert(isa<CompoundAssignOperator>(E) && + "Must be compound assignment operation"); + // Recurse on the LHS and RHS in here + AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); + AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); + + // Now check the outermost expression + const auto *ResultBT = E->getLHS()->getType()->getAs<BuiltinType>(); + const auto *RBT = cast<CompoundAssignOperator>(E) + ->getComputationResultType() + ->getAs<BuiltinType>(); + + // If both source and target are floating points. + if (ResultBT && ResultBT->isFloatingPoint() && RBT && RBT->isFloatingPoint()) + // Builtin FP kinds are ordered by increasing FP rank. + if (ResultBT->getKind() < RBT->getKind()) + // We don't want to warn for system macro. + if (!S.SourceMgr.isInSystemMacro(E->getOperatorLoc())) + // warn about dropping FP rank. + DiagnoseImpCast(S, E->getRHS(), E->getLHS()->getType(), + E->getOperatorLoc(), + diag::warn_impcast_float_result_precision); +} /// Diagnose an implicit cast from a floating point value to an integer value. static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, @@ -9249,14 +10364,24 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, llvm::APSInt IntegerValue(S.Context.getIntWidth(T), T->hasUnsignedIntegerRepresentation()); - if (Value.convertToInteger(IntegerValue, llvm::APFloat::rmTowardZero, - &isExact) == llvm::APFloat::opOK && - isExact) { + llvm::APFloat::opStatus Result = Value.convertToInteger( + IntegerValue, llvm::APFloat::rmTowardZero, &isExact); + + if (Result == llvm::APFloat::opOK && isExact) { if (IsLiteral) return; return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer, PruneWarnings); } + // Conversion of a floating-point value to a non-bool integer where the + // integral part cannot be represented by the integer type is undefined. + if (!IsBool && Result == llvm::APFloat::opInvalidOp) + return DiagnoseImpCast( + S, E, T, CContext, + IsLiteral ? diag::warn_impcast_literal_float_to_integer_out_of_range + : diag::warn_impcast_float_to_integer_out_of_range, + PruneWarnings); + unsigned DiagID = 0; if (IsLiteral) { // Warn on floating point literal to integer. @@ -9390,18 +10515,15 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, // Venture through the macro stacks to get to the source of macro arguments. // The new location is a better location than the complete location that was // passed in. - while (S.SourceMgr.isMacroArgExpansion(Loc)) - Loc = S.SourceMgr.getImmediateMacroCallerLoc(Loc); - - while (S.SourceMgr.isMacroArgExpansion(CC)) - CC = S.SourceMgr.getImmediateMacroCallerLoc(CC); + Loc = S.SourceMgr.getTopMacroCallerLoc(Loc); + CC = S.SourceMgr.getTopMacroCallerLoc(CC); // __null is usually wrapped in a macro. Go up a macro if that is the case. if (NullKind == Expr::NPCK_GNUNull && Loc.isMacroID()) { StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics( Loc, S.SourceMgr, S.getLangOpts()); if (MacroName == "NULL") - Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first; + Loc = S.SourceMgr.getImmediateExpansionRange(Loc).getBegin(); } // Only warn if the null and context location are in the same macro expansion. @@ -9591,7 +10713,7 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, return; return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_vector_scalar); } - + // If the vector cast is cast between two vectors of the same size, it is // a bitcast, not a conversion. if (S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target)) @@ -9772,7 +10894,7 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, // We also want to warn about it in -Wconversion. // So if -Wconversion is off, use a completely identical diagnostic // in the sign-compare group. - // The conditional-checking code will + // The conditional-checking code will if (ICContext) { DiagID = diag::warn_impcast_integer_sign_conditional; *ICContext = true; @@ -9793,7 +10915,7 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, Source = S.Context.getCanonicalType(SourceType).getTypePtr(); } } - + if (const EnumType *SourceEnum = Source->getAs<EnumType>()) if (const EnumType *TargetEnum = Target->getAs<EnumType>()) if (SourceEnum->getDecl()->hasNameForLinkage() && @@ -9802,7 +10924,7 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, if (S.SourceMgr.isInSystemMacro(CC)) return; - return DiagnoseImpCast(S, E, SourceType, T, CC, + return DiagnoseImpCast(S, E, SourceType, T, CC, diag::warn_impcast_different_enum_types); } } @@ -9841,7 +10963,7 @@ static void CheckConditionalOperator(Sema &S, ConditionalOperator *E, // ...then check whether it would have warned about either of the // candidates for a signedness conversion to the condition type. if (E->getType() == T) return; - + Suspicious = false; CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(), E->getType(), CC, &Suspicious); @@ -9868,7 +10990,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, if (E->isTypeDependent() || E->isValueDependent()) return; - + // For conditional operators, we analyze the arguments as if they // were being fed directly into the output. if (isa<ConditionalOperator>(E)) { @@ -9912,6 +11034,9 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, // And with simple assignments. if (BO->getOpcode() == BO_Assign) return AnalyzeAssignment(S, BO); + // And with compound assignments. + if (BO->isAssignmentOp()) + return AnalyzeCompoundAssignment(S, BO); } // These break the otherwise-useful invariant below. Fortunately, @@ -9955,7 +11080,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, ::CheckBoolLikeConversion(S, U->getSubExpr(), CC); } -/// Diagnose integer type and any valid implicit convertion to it. +/// Diagnose integer type and any valid implicit conversion to it. static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E, const QualType &IntT) { // Taking into account implicit conversions, // allow any integer. @@ -10018,7 +11143,7 @@ static bool IsInAnyMacroBody(const SourceManager &SM, SourceLocation Loc) { return false; } -/// \brief Diagnose pointers that are always non-null. +/// Diagnose pointers that are always non-null. /// \param E the expression containing the pointer /// \param NullKind NPCK_NotNull if E is a cast to bool, otherwise, E is /// compared to a null pointer @@ -10122,8 +11247,8 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, return; } - for (unsigned ArgNo : NonNull->args()) { - if (ArgNo == ParamNo) { + for (const ParamIdx &ArgNo : NonNull->args()) { + if (ArgNo.getASTIndex() == ParamNo) { ComplainAboutNonnullParamOrCall(NonNull); return; } @@ -10244,29 +11369,33 @@ void Sema::CheckForIntOverflow (Expr *E) { SmallVector<Expr *, 2> Exprs(1, E); do { - Expr *E = Exprs.pop_back_val(); + Expr *OriginalE = Exprs.pop_back_val(); + Expr *E = OriginalE->IgnoreParenCasts(); - if (isa<BinaryOperator>(E->IgnoreParenCasts())) { - E->IgnoreParenCasts()->EvaluateForOverflow(Context); + if (isa<BinaryOperator>(E)) { + E->EvaluateForOverflow(Context); continue; } - if (auto InitList = dyn_cast<InitListExpr>(E)) + if (auto InitList = dyn_cast<InitListExpr>(OriginalE)) Exprs.append(InitList->inits().begin(), InitList->inits().end()); - - if (isa<ObjCBoxedExpr>(E)) - E->IgnoreParenCasts()->EvaluateForOverflow(Context); + else if (isa<ObjCBoxedExpr>(OriginalE)) + E->EvaluateForOverflow(Context); + else if (auto Call = dyn_cast<CallExpr>(E)) + Exprs.append(Call->arg_begin(), Call->arg_end()); + else if (auto Message = dyn_cast<ObjCMessageExpr>(E)) + Exprs.append(Message->arg_begin(), Message->arg_end()); } while (!Exprs.empty()); } namespace { -/// \brief Visitor for expressions which looks for unsequenced operations on the +/// Visitor for expressions which looks for unsequenced operations on the /// same object. class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { using Base = EvaluatedExprVisitor<SequenceChecker>; - /// \brief A tree of sequenced regions within an expression. Two regions are + /// A tree of sequenced regions within an expression. Two regions are /// unsequenced if one is an ancestor or a descendent of the other. When we /// finish processing an expression with sequencing, such as a comma /// expression, we fold its tree nodes into its parent, since they are @@ -10280,7 +11409,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { SmallVector<Value, 8> Values; public: - /// \brief A region within an expression which may be sequenced with respect + /// A region within an expression which may be sequenced with respect /// to some other region. class Seq { friend class SequenceTree; @@ -10296,7 +11425,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { SequenceTree() { Values.push_back(Value(0)); } Seq root() const { return Seq(0); } - /// \brief Create a new sequence of operations, which is an unsequenced + /// Create a new sequence of operations, which is an unsequenced /// subset of \p Parent. This sequence of operations is sequenced with /// respect to other children of \p Parent. Seq allocate(Seq Parent) { @@ -10304,12 +11433,12 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { return Seq(Values.size() - 1); } - /// \brief Merge a sequence of operations into its parent. + /// Merge a sequence of operations into its parent. void merge(Seq S) { Values[S.Index].Merged = true; } - /// \brief Determine whether two operations are unsequenced. This operation + /// Determine whether two operations are unsequenced. This operation /// is asymmetric: \p Cur should be the more recent sequence, and \p Old /// should have been merged into its parent as appropriate. bool isUnsequenced(Seq Cur, Seq Old) { @@ -10324,7 +11453,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { } private: - /// \brief Pick a representative for a sequence. + /// Pick a representative for a sequence. unsigned representative(unsigned K) { if (Values[K].Merged) // Perform path compression as we go. @@ -10445,7 +11574,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { bool EvalOK = true; } *EvalTracker = nullptr; - /// \brief Find the object which is produced by the specified expression, + /// Find the object which is produced by the specified expression, /// if any. Object getObject(Expr *E, bool Mod) const { E = E->IgnoreParenCasts(); @@ -10467,7 +11596,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { return nullptr; } - /// \brief Note that an object was modified or used by an expression. + /// Note that an object was modified or used by an expression. void addUsage(UsageInfo &UI, Object O, Expr *Ref, UsageKind UK) { Usage &U = UI.Uses[UK]; if (!U.Use || !Tree.isUnsequenced(Region, U.Seq)) { @@ -10478,7 +11607,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { } } - /// \brief Check whether a modification or use conflicts with a prior usage. + /// Check whether a modification or use conflicts with a prior usage. void checkUsage(Object O, UsageInfo &UI, Expr *Ref, UsageKind OtherKind, bool IsModMod) { if (UI.Diagnosed) @@ -10857,23 +11986,18 @@ bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters, // information is added for it. diagnoseArrayStarInParamType(*this, PType, Param->getLocation()); - // MSVC destroys objects passed by value in the callee. Therefore a - // function definition which takes such a parameter must be able to call the - // object's destructor. However, we don't perform any direct access check - // on the dtor. - if (getLangOpts().CPlusPlus && Context.getTargetInfo() - .getCXXABI() - .areArgsDestroyedLeftToRightInCallee()) { - if (!Param->isInvalidDecl()) { - if (const RecordType *RT = Param->getType()->getAs<RecordType>()) { - CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl()); - if (!ClassDecl->isInvalidDecl() && - !ClassDecl->hasIrrelevantDestructor() && - !ClassDecl->isDependentContext()) { - CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl); - MarkFunctionReferenced(Param->getLocation(), Destructor); - DiagnoseUseOfDecl(Destructor, Param->getLocation()); - } + // If the parameter is a c++ class type and it has to be destructed in the + // callee function, declare the destructor so that it can be called by the + // callee function. Do not perform any direct access check on the dtor here. + if (!Param->isInvalidDecl()) { + if (CXXRecordDecl *ClassDecl = Param->getType()->getAsCXXRecordDecl()) { + if (!ClassDecl->isInvalidDecl() && + !ClassDecl->hasIrrelevantDestructor() && + !ClassDecl->isDependentContext() && + ClassDecl->isParamDestroyedInCallee()) { + CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl); + MarkFunctionReferenced(Param->getLocation(), Destructor); + DiagnoseUseOfDecl(Destructor, Param->getLocation()); } } } @@ -10956,7 +12080,7 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { << TRange << Op->getSourceRange(); } -/// \brief Check whether this array fits the idiom of a size-one tail padded +/// Check whether this array fits the idiom of a size-one tail padded /// array member of a struct. /// /// We avoid emitting out-of-bounds access warnings for such arrays as they are @@ -11026,9 +12150,9 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, const NamedDecl *ND = nullptr; if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) - ND = dyn_cast<NamedDecl>(DRE->getDecl()); + ND = DRE->getDecl(); if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr)) - ND = dyn_cast<NamedDecl>(ME->getMemberDecl()); + ND = ME->getMemberDecl(); if (index.isUnsigned() || !index.isNegative()) { llvm::APInt size = ArrayTy->getSize(); @@ -11111,9 +12235,9 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, dyn_cast<ArraySubscriptExpr>(BaseExpr)) BaseExpr = ASE->getBase()->IgnoreParenCasts(); if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) - ND = dyn_cast<NamedDecl>(DRE->getDecl()); + ND = DRE->getDecl(); if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr)) - ND = dyn_cast<NamedDecl>(ME->getMemberDecl()); + ND = ME->getMemberDecl(); } if (ND) @@ -11131,7 +12255,12 @@ void Sema::CheckArrayAccess(const Expr *expr) { const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(expr); CheckArrayAccess(ASE->getBase(), ASE->getIdx(), ASE, AllowOnePastEnd > 0); - return; + expr = ASE->getBase(); + break; + } + case Stmt::MemberExprClass: { + expr = cast<MemberExpr>(expr)->getBase(); + break; } case Stmt::OMPArraySectionExprClass: { const OMPArraySectionExpr *ASE = cast<OMPArraySectionExpr>(expr); @@ -11315,11 +12444,11 @@ namespace { } void VisitBlockExpr(BlockExpr *block) { - // Look inside nested blocks + // Look inside nested blocks if (block->getBlockDecl()->capturesVariable(Variable)) Visit(block->getBlockDecl()->getBody()); } - + void VisitOpaqueValueExpr(OpaqueValueExpr *OVE) { if (Capturer) return; if (OVE->getSourceExpr()) @@ -11372,7 +12501,7 @@ static Expr *findCapturingExpr(Sema &S, Expr *e, RetainCycleOwner &owner) { } } } - + BlockExpr *block = dyn_cast<BlockExpr>(e); if (!block || !block->getBlockDecl()->capturesVariable(owner.Variable)) return nullptr; @@ -11541,7 +12670,7 @@ void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) { if (ArgRE->isObjCSelfExpr()) { Diag(Message->getSourceRange().getBegin(), diag::warn_objc_circular_container) - << ArgRE->getDecl()->getName() << StringRef("super"); + << ArgRE->getDecl() << StringRef("'super'"); } } } else { @@ -11557,11 +12686,11 @@ void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) { ValueDecl *Decl = ReceiverRE->getDecl(); Diag(Message->getSourceRange().getBegin(), diag::warn_objc_circular_container) - << Decl->getName() << Decl->getName(); + << Decl << Decl; if (!ArgRE->isObjCSelfExpr()) { Diag(Decl->getLocation(), diag::note_objc_circular_container_declared_here) - << Decl->getName(); + << Decl; } } } @@ -11571,10 +12700,10 @@ void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) { ObjCIvarDecl *Decl = IvarRE->getDecl(); Diag(Message->getSourceRange().getBegin(), diag::warn_objc_circular_container) - << Decl->getName() << Decl->getName(); + << Decl << Decl; Diag(Decl->getLocation(), diag::note_objc_circular_container_declared_here) - << Decl->getName(); + << Decl; } } } @@ -11625,12 +12754,12 @@ void Sema::checkRetainCycles(VarDecl *Var, Expr *Init) { RetainCycleOwner Owner; if (!considerVariable(Var, /*DeclRefExpr=*/nullptr, Owner)) return; - + // Because we don't have an expression for the variable, we have to set the // location explicitly here. Owner.Loc = Var->getLocation(); Owner.Range = Var->getSourceRange(); - + if (Expr *Capturer = findCapturingExpr(*this, Init, Owner)) diagnoseRetainCycle(*this, Capturer, Owner); } @@ -11703,7 +12832,7 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc, if (PD) LHSType = PD->getType(); } - + if (LHSType.isNull()) LHSType = LHS->getType(); @@ -11720,14 +12849,14 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc, // FIXME. Check for other life times. if (LT != Qualifiers::OCL_None) return; - + if (PRE) { if (PRE->isImplicitProperty()) return; const ObjCPropertyDecl *PD = PRE->getExplicitProperty(); if (!PD) return; - + unsigned Attributes = PD->getPropertyAttributes(); if (Attributes & ObjCPropertyDecl::OBJC_PR_assign) { // when 'assign' attribute was not explicitly specified @@ -11737,7 +12866,7 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc, if (!(AsWrittenAttr & ObjCPropertyDecl::OBJC_PR_assign) && LHSType->isObjCRetainableType()) return; - + while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) { if (cast->getCastKind() == CK_ARCConsumeObject) { Diag(Loc, diag::warn_arc_retained_property_assign) @@ -11967,7 +13096,7 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2); -/// \brief Check if two enumeration types are layout-compatible. +/// Check if two enumeration types are layout-compatible. static bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) { // C++11 [dcl.enum] p8: // Two enumeration types are layout-compatible if they have the same @@ -11976,7 +13105,7 @@ static bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) { C.hasSameType(ED1->getIntegerType(), ED2->getIntegerType()); } -/// \brief Check if two fields are layout-compatible. +/// Check if two fields are layout-compatible. static bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, FieldDecl *Field2) { if (!isLayoutCompatible(C, Field1->getType(), Field2->getType())) @@ -11997,7 +13126,7 @@ static bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, return true; } -/// \brief Check if two standard-layout structs are layout-compatible. +/// Check if two standard-layout structs are layout-compatible. /// (C++11 [class.mem] p17) static bool isLayoutCompatibleStruct(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) { @@ -12041,7 +13170,7 @@ static bool isLayoutCompatibleStruct(ASTContext &C, RecordDecl *RD1, return true; } -/// \brief Check if two standard-layout unions are layout-compatible. +/// Check if two standard-layout unions are layout-compatible. /// (C++11 [class.mem] p18) static bool isLayoutCompatibleUnion(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) { @@ -12080,7 +13209,7 @@ static bool isLayoutCompatible(ASTContext &C, RecordDecl *RD1, return isLayoutCompatibleStruct(C, RD1, RD2); } -/// \brief Check if two types are layout-compatible in C++11 sense. +/// Check if two types are layout-compatible in C++11 sense. static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) { if (T1.isNull() || T2.isNull()) return false; @@ -12118,7 +13247,7 @@ static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) { //===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----// -/// \brief Given a type tag expression find the type tag itself. +/// Given a type tag expression find the type tag itself. /// /// \param TypeExpr Type tag expression, as it appears in user's code. /// @@ -12189,7 +13318,7 @@ static bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx, } } -/// \brief Retrieve the C type corresponding to type tag TypeExpr. +/// Retrieve the C type corresponding to type tag TypeExpr. /// /// \param TypeExpr Expression that specifies a type tag. /// @@ -12283,13 +13412,13 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, bool IsPointerAttr = Attr->getIsPointer(); // Retrieve the argument representing the 'type_tag'. - if (Attr->getTypeTagIdx() >= ExprArgs.size()) { - // Add 1 to display the user's specified value. + unsigned TypeTagIdxAST = Attr->getTypeTagIdx().getASTIndex(); + if (TypeTagIdxAST >= ExprArgs.size()) { Diag(CallSiteLoc, diag::err_tag_index_out_of_range) - << 0 << Attr->getTypeTagIdx() + 1; + << 0 << Attr->getTypeTagIdx().getSourceIndex(); return; } - const Expr *TypeTagExpr = ExprArgs[Attr->getTypeTagIdx()]; + const Expr *TypeTagExpr = ExprArgs[TypeTagIdxAST]; bool FoundWrongKind; TypeTagData TypeInfo; if (!GetMatchingCType(ArgumentKind, TypeTagExpr, Context, @@ -12303,13 +13432,13 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, } // Retrieve the argument representing the 'arg_idx'. - if (Attr->getArgumentIdx() >= ExprArgs.size()) { - // Add 1 to display the user's specified value. + unsigned ArgumentIdxAST = Attr->getArgumentIdx().getASTIndex(); + if (ArgumentIdxAST >= ExprArgs.size()) { Diag(CallSiteLoc, diag::err_tag_index_out_of_range) - << 1 << Attr->getArgumentIdx() + 1; + << 1 << Attr->getArgumentIdx().getSourceIndex(); return; } - const Expr *ArgumentExpr = ExprArgs[Attr->getArgumentIdx()]; + const Expr *ArgumentExpr = ExprArgs[ArgumentIdxAST]; if (IsPointerAttr) { // Skip implicit cast of pointer to `void *' (as a function argument). if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgumentExpr)) diff --git a/gnu/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp b/gnu/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp index aecc98e297e..501797b087a 100644 --- a/gnu/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp +++ b/gnu/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp @@ -31,6 +31,7 @@ #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" @@ -58,7 +59,7 @@ static bool isFunctionOrMethod(const Decl *D) { return (D->getFunctionType() != nullptr) || isa<ObjCMethodDecl>(D); } -/// \brief Return true if the given decl has function type (function or +/// Return true if the given decl has function type (function or /// function-typed variable) or an Objective-C method or a block. static bool isFunctionOrMethodOrBlock(const Decl *D) { return isFunctionOrMethod(D) || isa<BlockDecl>(D); @@ -87,7 +88,7 @@ static bool hasFunctionProto(const Decl *D) { static unsigned getFunctionOrMethodNumParams(const Decl *D) { if (const FunctionType *FnTy = D->getFunctionType()) return cast<FunctionProtoType>(FnTy)->getNumParams(); - if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) + if (const auto *BD = dyn_cast<BlockDecl>(D)) return BD->getNumParams(); return cast<ObjCMethodDecl>(D)->param_size(); } @@ -95,7 +96,7 @@ static unsigned getFunctionOrMethodNumParams(const Decl *D) { static QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) { if (const FunctionType *FnTy = D->getFunctionType()) return cast<FunctionProtoType>(FnTy)->getParamType(Idx); - if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) + if (const auto *BD = dyn_cast<BlockDecl>(D)) return BD->getParamDecl(Idx)->getType(); return cast<ObjCMethodDecl>(D)->parameters()[Idx]->getType(); @@ -113,7 +114,7 @@ static SourceRange getFunctionOrMethodParamRange(const Decl *D, unsigned Idx) { static QualType getFunctionOrMethodResultType(const Decl *D) { if (const FunctionType *FnTy = D->getFunctionType()) - return cast<FunctionType>(FnTy)->getReturnType(); + return FnTy->getReturnType(); return cast<ObjCMethodDecl>(D)->getReturnType(); } @@ -126,24 +127,21 @@ static SourceRange getFunctionOrMethodResultSourceRange(const Decl *D) { } static bool isFunctionOrMethodVariadic(const Decl *D) { - if (const FunctionType *FnTy = D->getFunctionType()) { - const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy); - return proto->isVariadic(); - } - if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) + if (const FunctionType *FnTy = D->getFunctionType()) + return cast<FunctionProtoType>(FnTy)->isVariadic(); + if (const auto *BD = dyn_cast<BlockDecl>(D)) return BD->isVariadic(); - return cast<ObjCMethodDecl>(D)->isVariadic(); } static bool isInstanceMethod(const Decl *D) { - if (const CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) + if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(D)) return MethodDecl->isInstance(); return false; } static inline bool isNSStringType(QualType T, ASTContext &Ctx) { - const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>(); + const auto *PT = T->getAs<ObjCObjectPointerType>(); if (!PT) return false; @@ -159,11 +157,11 @@ static inline bool isNSStringType(QualType T, ASTContext &Ctx) { } static inline bool isCFStringType(QualType T, ASTContext &Ctx) { - const PointerType *PT = T->getAs<PointerType>(); + const auto *PT = T->getAs<PointerType>(); if (!PT) return false; - const RecordType *RT = PT->getPointeeType()->getAs<RecordType>(); + const auto *RT = PT->getPointeeType()->getAs<RecordType>(); if (!RT) return false; @@ -174,89 +172,86 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) { return RD->getIdentifier() == &Ctx.Idents.get("__CFString"); } -static unsigned getNumAttributeArgs(const AttributeList &Attr) { +static unsigned getNumAttributeArgs(const ParsedAttr &AL) { // FIXME: Include the type in the argument list. - return Attr.getNumArgs() + Attr.hasParsedType(); + return AL.getNumArgs() + AL.hasParsedType(); } template <typename Compare> -static bool checkAttributeNumArgsImpl(Sema &S, const AttributeList &Attr, +static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL, unsigned Num, unsigned Diag, Compare Comp) { - if (Comp(getNumAttributeArgs(Attr), Num)) { - S.Diag(Attr.getLoc(), Diag) << Attr.getName() << Num; + if (Comp(getNumAttributeArgs(AL), Num)) { + S.Diag(AL.getLoc(), Diag) << AL.getName() << Num; return false; } return true; } -/// \brief Check if the attribute has exactly as many args as Num. May +/// Check if the attribute has exactly as many args as Num. May /// output an error. -static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr, - unsigned Num) { - return checkAttributeNumArgsImpl(S, Attr, Num, +static bool checkAttributeNumArgs(Sema &S, const ParsedAttr &AL, unsigned Num) { + return checkAttributeNumArgsImpl(S, AL, Num, diag::err_attribute_wrong_number_arguments, std::not_equal_to<unsigned>()); } -/// \brief Check if the attribute has at least as many args as Num. May +/// Check if the attribute has at least as many args as Num. May /// output an error. -static bool checkAttributeAtLeastNumArgs(Sema &S, const AttributeList &Attr, +static bool checkAttributeAtLeastNumArgs(Sema &S, const ParsedAttr &AL, unsigned Num) { - return checkAttributeNumArgsImpl(S, Attr, Num, + return checkAttributeNumArgsImpl(S, AL, Num, diag::err_attribute_too_few_arguments, std::less<unsigned>()); } -/// \brief Check if the attribute has at most as many args as Num. May +/// Check if the attribute has at most as many args as Num. May /// output an error. -static bool checkAttributeAtMostNumArgs(Sema &S, const AttributeList &Attr, - unsigned Num) { - return checkAttributeNumArgsImpl(S, Attr, Num, +static bool checkAttributeAtMostNumArgs(Sema &S, const ParsedAttr &AL, + unsigned Num) { + return checkAttributeNumArgsImpl(S, AL, Num, diag::err_attribute_too_many_arguments, std::greater<unsigned>()); } -/// \brief A helper function to provide Attribute Location for the Attr types -/// AND the AttributeList. +/// A helper function to provide Attribute Location for the Attr types +/// AND the ParsedAttr. template <typename AttrInfo> -static typename std::enable_if<std::is_base_of<clang::Attr, AttrInfo>::value, +static typename std::enable_if<std::is_base_of<Attr, AttrInfo>::value, SourceLocation>::type -getAttrLoc(const AttrInfo &Attr) { - return Attr.getLocation(); -} -static SourceLocation getAttrLoc(const clang::AttributeList &Attr) { - return Attr.getLoc(); +getAttrLoc(const AttrInfo &AL) { + return AL.getLocation(); } +static SourceLocation getAttrLoc(const ParsedAttr &AL) { return AL.getLoc(); } -/// \brief A helper function to provide Attribute Name for the Attr types -/// AND the AttributeList. +/// A helper function to provide Attribute Name for the Attr types +/// AND the ParsedAttr. template <typename AttrInfo> -static typename std::enable_if<std::is_base_of<clang::Attr, AttrInfo>::value, +static typename std::enable_if<std::is_base_of<Attr, AttrInfo>::value, const AttrInfo *>::type -getAttrName(const AttrInfo &Attr) { - return &Attr; +getAttrName(const AttrInfo &AL) { + return &AL; } -static const IdentifierInfo *getAttrName(const clang::AttributeList &Attr) { - return Attr.getName(); +static const IdentifierInfo *getAttrName(const ParsedAttr &AL) { + return AL.getName(); } -/// \brief If Expr is a valid integer constant, get the value of the integer +/// If Expr is a valid integer constant, get the value of the integer /// expression and return success or failure. May output an error. -template<typename AttrInfo> -static bool checkUInt32Argument(Sema &S, const AttrInfo& Attr, const Expr *Expr, +template <typename AttrInfo> +static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr, uint32_t &Val, unsigned Idx = UINT_MAX) { llvm::APSInt I(32); if (Expr->isTypeDependent() || Expr->isValueDependent() || !Expr->isIntegerConstantExpr(I, S.Context)) { if (Idx != UINT_MAX) - S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_n_type) - << getAttrName(Attr) << Idx << AANT_ArgumentIntegerConstant + S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) + << getAttrName(AI) << Idx << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); else - S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_type) - << getAttrName(Attr) << AANT_ArgumentIntegerConstant + S.Diag(getAttrLoc(AI), diag::err_attribute_argument_type) + << getAttrName(AI) << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); return false; } @@ -271,14 +266,14 @@ static bool checkUInt32Argument(Sema &S, const AttrInfo& Attr, const Expr *Expr, return true; } -/// \brief Wrapper around checkUInt32Argument, with an extra check to be sure +/// Wrapper around checkUInt32Argument, with an extra check to be sure /// that the result will fit into a regular (signed) int. All args have the same /// purpose as they do in checkUInt32Argument. -template<typename AttrInfo> -static bool checkPositiveIntArgument(Sema &S, const AttrInfo& Attr, const Expr *Expr, +template <typename AttrInfo> +static bool checkPositiveIntArgument(Sema &S, const AttrInfo &AI, const Expr *Expr, int &Val, unsigned Idx = UINT_MAX) { uint32_t UVal; - if (!checkUInt32Argument(S, Attr, Expr, UVal, Idx)) + if (!checkUInt32Argument(S, AI, Expr, UVal, Idx)) return false; if (UVal > (uint32_t)std::numeric_limits<int>::max()) { @@ -293,12 +288,12 @@ static bool checkPositiveIntArgument(Sema &S, const AttrInfo& Attr, const Expr * return true; } -/// \brief Diagnose mutually exclusive attributes when present on a given +/// Diagnose mutually exclusive attributes when present on a given /// declaration. Returns true if diagnosed. template <typename AttrTy> static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range, IdentifierInfo *Ident) { - if (AttrTy *A = D->getAttr<AttrTy>()) { + if (const auto *A = D->getAttr<AttrTy>()) { S.Diag(Range.getBegin(), diag::err_attributes_are_not_compatible) << Ident << A; S.Diag(A->getLocation(), diag::note_conflicting_attribute); @@ -307,14 +302,14 @@ static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range, return false; } -/// \brief Check if IdxExpr is a valid parameter index for a function or +/// Check if IdxExpr is a valid parameter index for a function or /// instance method D. May output an error. /// /// \returns true if IdxExpr is a valid index. template <typename AttrInfo> static bool checkFunctionOrMethodParameterIndex( - Sema &S, const Decl *D, const AttrInfo &Attr, unsigned AttrArgNum, - const Expr *IdxExpr, uint64_t &Idx, bool AllowImplicitThis = false) { + Sema &S, const Decl *D, const AttrInfo &AI, unsigned AttrArgNum, + const Expr *IdxExpr, ParamIdx &Idx, bool CanIndexImplicitThis = false) { assert(isFunctionOrMethodOrBlock(D)); // In C++ the implicit 'this' function parameter also counts. @@ -328,44 +323,43 @@ static bool checkFunctionOrMethodParameterIndex( llvm::APSInt IdxInt; if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || !IdxExpr->isIntegerConstantExpr(IdxInt, S.Context)) { - S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_n_type) - << getAttrName(Attr) << AttrArgNum << AANT_ArgumentIntegerConstant + S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) + << getAttrName(AI) << AttrArgNum << AANT_ArgumentIntegerConstant << IdxExpr->getSourceRange(); return false; } - Idx = IdxInt.getLimitedValue(); - if (Idx < 1 || (!IV && Idx > NumParams)) { - S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_out_of_bounds) - << getAttrName(Attr) << AttrArgNum << IdxExpr->getSourceRange(); + unsigned IdxSource = IdxInt.getLimitedValue(UINT_MAX); + if (IdxSource < 1 || (!IV && IdxSource > NumParams)) { + S.Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds) + << getAttrName(AI) << AttrArgNum << IdxExpr->getSourceRange(); return false; } - Idx--; // Convert to zero-based. - if (HasImplicitThisParam && !AllowImplicitThis) { - if (Idx == 0) { - S.Diag(getAttrLoc(Attr), + if (HasImplicitThisParam && !CanIndexImplicitThis) { + if (IdxSource == 1) { + S.Diag(getAttrLoc(AI), diag::err_attribute_invalid_implicit_this_argument) - << getAttrName(Attr) << IdxExpr->getSourceRange(); + << getAttrName(AI) << IdxExpr->getSourceRange(); return false; } - --Idx; } + Idx = ParamIdx(IdxSource, D); return true; } -/// \brief Check if the argument \p ArgNum of \p Attr is a ASCII string literal. +/// Check if the argument \p ArgNum of \p Attr is a ASCII string literal. /// If not emit an error and return false. If the argument is an identifier it /// will emit an error with a fixit hint and treat it as if it was a string /// literal. -bool Sema::checkStringLiteralArgumentAttr(const AttributeList &Attr, - unsigned ArgNum, StringRef &Str, +bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum, + StringRef &Str, SourceLocation *ArgLocation) { // Look for identifiers. If we have one emit a hint to fix it to a literal. - if (Attr.isArgIdent(ArgNum)) { - IdentifierLoc *Loc = Attr.getArgAsIdent(ArgNum); + if (AL.isArgIdent(ArgNum)) { + IdentifierLoc *Loc = AL.getArgAsIdent(ArgNum); Diag(Loc->Loc, diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentString + << AL.getName() << AANT_ArgumentString << FixItHint::CreateInsertion(Loc->Loc, "\"") << FixItHint::CreateInsertion(getLocForEndOfToken(Loc->Loc), "\""); Str = Loc->Ident->getName(); @@ -375,14 +369,14 @@ bool Sema::checkStringLiteralArgumentAttr(const AttributeList &Attr, } // Now check for an actual string literal. - Expr *ArgExpr = Attr.getArgAsExpr(ArgNum); - StringLiteral *Literal = dyn_cast<StringLiteral>(ArgExpr->IgnoreParenCasts()); + Expr *ArgExpr = AL.getArgAsExpr(ArgNum); + const auto *Literal = dyn_cast<StringLiteral>(ArgExpr->IgnoreParenCasts()); if (ArgLocation) *ArgLocation = ArgExpr->getLocStart(); if (!Literal || !Literal->isAscii()) { Diag(ArgExpr->getLocStart(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentString; + << AL.getName() << AANT_ArgumentString; return false; } @@ -390,35 +384,34 @@ bool Sema::checkStringLiteralArgumentAttr(const AttributeList &Attr, return true; } -/// \brief Applies the given attribute to the Decl without performing any +/// Applies the given attribute to the Decl without performing any /// additional semantic checking. template <typename AttrType> -static void handleSimpleAttribute(Sema &S, Decl *D, - const AttributeList &Attr) { - D->addAttr(::new (S.Context) AttrType(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); +static void handleSimpleAttribute(Sema &S, Decl *D, const ParsedAttr &AL) { + D->addAttr(::new (S.Context) AttrType(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } template <typename AttrType> static void handleSimpleAttributeWithExclusions(Sema &S, Decl *D, - const AttributeList &Attr) { - handleSimpleAttribute<AttrType>(S, D, Attr); + const ParsedAttr &AL) { + handleSimpleAttribute<AttrType>(S, D, AL); } -/// \brief Applies the given attribute to the Decl so long as the Decl doesn't +/// Applies the given attribute to the Decl so long as the Decl doesn't /// already have one of the given incompatible attributes. template <typename AttrType, typename IncompatibleAttrType, typename... IncompatibleAttrTypes> static void handleSimpleAttributeWithExclusions(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, Attr.getRange(), - Attr.getName())) + const ParsedAttr &AL) { + if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL.getRange(), + AL.getName())) return; handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, - Attr); + AL); } -/// \brief Check if the passed-in expression is of type int or bool. +/// Check if the passed-in expression is of type int or bool. static bool isIntOrBool(Expr *Exp) { QualType QT = Exp->getType(); return QT->isBooleanType() || QT->isIntegerType(); @@ -441,17 +434,17 @@ static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) { return true; } -/// \brief Check if passed in Decl is a pointer type. +/// Check if passed in Decl is a pointer type. /// Note that this function may produce an error message. /// \return true if the Decl is a pointer type; false otherwise static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D, - const AttributeList &Attr) { - const ValueDecl *vd = cast<ValueDecl>(D); - QualType QT = vd->getType(); + const ParsedAttr &AL) { + const auto *VD = cast<ValueDecl>(D); + QualType QT = VD->getType(); if (QT->isAnyPointerType()) return true; - if (const RecordType *RT = QT->getAs<RecordType>()) { + if (const auto *RT = QT->getAs<RecordType>()) { // If it's an incomplete type, it could be a smart pointer; skip it. // (We don't want to force template instantiation if we can avoid it, // since that would alter the order in which templates are instantiated.) @@ -462,19 +455,19 @@ static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D, return true; } - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_pointer) - << Attr.getName() << QT; + S.Diag(AL.getLoc(), diag::warn_thread_attribute_decl_not_pointer) + << AL.getName() << QT; return false; } -/// \brief Checks that the passed in QualType either is of RecordType or points +/// Checks that the passed in QualType either is of RecordType or points /// to RecordType. Returns the relevant RecordType, null if it does not exit. static const RecordType *getRecordType(QualType QT) { - if (const RecordType *RT = QT->getAs<RecordType>()) + if (const auto *RT = QT->getAs<RecordType>()) return RT; // Now check if we point to record type. - if (const PointerType *PT = QT->getAs<PointerType>()) + if (const auto *PT = QT->getAs<PointerType>()) return PT->getPointeeType()->getAs<RecordType>(); return nullptr; @@ -501,7 +494,7 @@ static bool checkRecordTypeForCapability(Sema &S, QualType Ty) { return true; // Else check if any base classes have a capability. - if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) { + if (const auto *CRD = dyn_cast<CXXRecordDecl>(RD)) { CXXBasePaths BPaths(false, false); if (CRD->lookupInBases([](const CXXBaseSpecifier *BS, CXXBasePath &) { const auto *Type = BS->getType()->getAs<RecordType>(); @@ -559,18 +552,18 @@ static bool isCapabilityExpr(Sema &S, const Expr *Ex) { return typeHasCapability(S, Ex->getType()); } -/// \brief Checks that all attribute arguments, starting from Sidx, resolve to +/// Checks that all attribute arguments, starting from Sidx, resolve to /// a capability object. /// \param Sidx The attribute argument index to start checking with. /// \param ParamIdxOk Whether an argument can be indexing into a function /// parameter list. static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, - const AttributeList &Attr, + const ParsedAttr &AL, SmallVectorImpl<Expr *> &Args, int Sidx = 0, bool ParamIdxOk = false) { - for (unsigned Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) { - Expr *ArgExp = Attr.getArgAsExpr(Idx); + for (unsigned Idx = Sidx; Idx < AL.getNumArgs(); ++Idx) { + Expr *ArgExp = AL.getArgAsExpr(Idx); if (ArgExp->isTypeDependent()) { // FIXME -- need to check this again on template instantiation @@ -578,7 +571,7 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, continue; } - if (StringLiteral *StrLit = dyn_cast<StringLiteral>(ArgExp)) { + if (const auto *StrLit = dyn_cast<StringLiteral>(ArgExp)) { if (StrLit->getLength() == 0 || (StrLit->isAscii() && StrLit->getString() == StringRef("*"))) { // Pass empty strings to the analyzer without warnings. @@ -589,8 +582,7 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // We allow constant strings to be used as a placeholder for expressions // that are not valid C++ syntax, but warn that they are ignored. - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_ignored) << - Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_thread_attribute_ignored) << AL.getName(); Args.push_back(ArgExp); continue; } @@ -599,9 +591,9 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // A pointer to member expression of the form &MyClass::mu is treated // specially -- we need to look at the type of the member. - if (UnaryOperator *UOp = dyn_cast<UnaryOperator>(ArgExp)) + if (const auto *UOp = dyn_cast<UnaryOperator>(ArgExp)) if (UOp->getOpcode() == UO_AddrOf) - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(UOp->getSubExpr())) + if (const auto *DRE = dyn_cast<DeclRefExpr>(UOp->getSubExpr())) if (DRE->getDecl()->isCXXInstanceMember()) ArgTy = DRE->getDecl()->getType(); @@ -610,16 +602,16 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // Now check if we index into a record type function param. if(!RT && ParamIdxOk) { - FunctionDecl *FD = dyn_cast<FunctionDecl>(D); - IntegerLiteral *IL = dyn_cast<IntegerLiteral>(ArgExp); + const auto *FD = dyn_cast<FunctionDecl>(D); + const auto *IL = dyn_cast<IntegerLiteral>(ArgExp); if(FD && IL) { unsigned int NumParams = FD->getNumParams(); llvm::APInt ArgValue = IL->getValue(); uint64_t ParamIdxFromOne = ArgValue.getZExtValue(); uint64_t ParamIdxFromZero = ParamIdxFromOne - 1; - if(!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_range) - << Attr.getName() << Idx + 1 << NumParams; + if (!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_range) + << AL.getName() << Idx + 1 << NumParams; continue; } ArgTy = FD->getParamDecl(ParamIdxFromZero)->getType(); @@ -631,8 +623,8 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // capability may be on the type, and the expression is a capability // boolean logic expression. Eg) requires_capability(A || B && !C) if (!typeHasCapability(S, ArgTy) && !isCapabilityExpr(S, ArgExp)) - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable) - << Attr.getName() << ArgTy; + S.Diag(AL.getLoc(), diag::warn_thread_attribute_argument_not_lockable) + << AL.getName() << ArgTy; Args.push_back(ArgExp); } @@ -642,22 +634,20 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // Attribute Implementations //===----------------------------------------------------------------------===// -static void handlePtGuardedVarAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!threadSafetyCheckIsPointer(S, D, Attr)) +static void handlePtGuardedVarAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!threadSafetyCheckIsPointer(S, D, AL)) return; D->addAttr(::new (S.Context) - PtGuardedVarAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + PtGuardedVarAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static bool checkGuardedByAttrCommon(Sema &S, Decl *D, - const AttributeList &Attr, - Expr* &Arg) { - SmallVector<Expr*, 1> Args; +static bool checkGuardedByAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, + Expr *&Arg) { + SmallVector<Expr *, 1> Args; // check that all arguments are lockable objects - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args); unsigned Size = Args.size(); if (Size != 1) return false; @@ -667,273 +657,239 @@ static bool checkGuardedByAttrCommon(Sema &S, Decl *D, return true; } -static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Expr *Arg = nullptr; - if (!checkGuardedByAttrCommon(S, D, Attr, Arg)) + if (!checkGuardedByAttrCommon(S, D, AL, Arg)) return; - D->addAttr(::new (S.Context) GuardedByAttr(Attr.getRange(), S.Context, Arg, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) GuardedByAttr( + AL.getRange(), S.Context, Arg, AL.getAttributeSpellingListIndex())); } -static void handlePtGuardedByAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handlePtGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Expr *Arg = nullptr; - if (!checkGuardedByAttrCommon(S, D, Attr, Arg)) + if (!checkGuardedByAttrCommon(S, D, AL, Arg)) return; - if (!threadSafetyCheckIsPointer(S, D, Attr)) + if (!threadSafetyCheckIsPointer(S, D, AL)) return; - D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getRange(), - S.Context, Arg, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) PtGuardedByAttr( + AL.getRange(), S.Context, Arg, AL.getAttributeSpellingListIndex())); } -static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, - const AttributeList &Attr, +static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, SmallVectorImpl<Expr *> &Args) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return false; // Check that this attribute only applies to lockable types. QualType QT = cast<ValueDecl>(D)->getType(); if (!QT->isDependentType() && !typeHasCapability(S, QT)) { - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_lockable) - << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_thread_attribute_decl_not_lockable) + << AL.getName(); return false; } // Check that all arguments are lockable objects. - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args); if (Args.empty()) return false; return true; } -static void handleAcquiredAfterAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - SmallVector<Expr*, 1> Args; - if (!checkAcquireOrderAttrCommon(S, D, Attr, Args)) +static void handleAcquiredAfterAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + SmallVector<Expr *, 1> Args; + if (!checkAcquireOrderAttrCommon(S, D, AL, Args)) return; Expr **StartArg = &Args[0]; - D->addAttr(::new (S.Context) - AcquiredAfterAttr(Attr.getRange(), S.Context, - StartArg, Args.size(), - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AcquiredAfterAttr( + AL.getRange(), S.Context, StartArg, Args.size(), + AL.getAttributeSpellingListIndex())); } -static void handleAcquiredBeforeAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - SmallVector<Expr*, 1> Args; - if (!checkAcquireOrderAttrCommon(S, D, Attr, Args)) +static void handleAcquiredBeforeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + SmallVector<Expr *, 1> Args; + if (!checkAcquireOrderAttrCommon(S, D, AL, Args)) return; Expr **StartArg = &Args[0]; - D->addAttr(::new (S.Context) - AcquiredBeforeAttr(Attr.getRange(), S.Context, - StartArg, Args.size(), - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AcquiredBeforeAttr( + AL.getRange(), S.Context, StartArg, Args.size(), + AL.getAttributeSpellingListIndex())); } -static bool checkLockFunAttrCommon(Sema &S, Decl *D, - const AttributeList &Attr, +static bool checkLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, SmallVectorImpl<Expr *> &Args) { // zero or more arguments ok // check that all arguments are lockable objects - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 0, /*ParamIdxOk=*/true); return true; } -static void handleAssertSharedLockAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - SmallVector<Expr*, 1> Args; - if (!checkLockFunAttrCommon(S, D, Attr, Args)) +static void handleAssertSharedLockAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + SmallVector<Expr *, 1> Args; + if (!checkLockFunAttrCommon(S, D, AL, Args)) return; unsigned Size = Args.size(); Expr **StartArg = Size == 0 ? nullptr : &Args[0]; D->addAttr(::new (S.Context) - AssertSharedLockAttr(Attr.getRange(), S.Context, StartArg, Size, - Attr.getAttributeSpellingListIndex())); + AssertSharedLockAttr(AL.getRange(), S.Context, StartArg, Size, + AL.getAttributeSpellingListIndex())); } static void handleAssertExclusiveLockAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - SmallVector<Expr*, 1> Args; - if (!checkLockFunAttrCommon(S, D, Attr, Args)) + const ParsedAttr &AL) { + SmallVector<Expr *, 1> Args; + if (!checkLockFunAttrCommon(S, D, AL, Args)) return; unsigned Size = Args.size(); Expr **StartArg = Size == 0 ? nullptr : &Args[0]; - D->addAttr(::new (S.Context) - AssertExclusiveLockAttr(Attr.getRange(), S.Context, - StartArg, Size, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AssertExclusiveLockAttr( + AL.getRange(), S.Context, StartArg, Size, + AL.getAttributeSpellingListIndex())); } -/// \brief Checks to be sure that the given parameter number is in bounds, and is -/// an integral type. Will emit appropriate diagnostics if this returns +/// Checks to be sure that the given parameter number is in bounds, and +/// is an integral type. Will emit appropriate diagnostics if this returns /// false. /// -/// FuncParamNo is expected to be from the user, so is base-1. AttrArgNo is used -/// to actually retrieve the argument, so it's base-0. +/// AttrArgNo is used to actually retrieve the argument, so it's base-0. template <typename AttrInfo> static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD, - const AttrInfo &Attr, Expr *AttrArg, - unsigned FuncParamNo, unsigned AttrArgNo, - bool AllowDependentType = false) { - uint64_t Idx; - if (!checkFunctionOrMethodParameterIndex(S, FD, Attr, FuncParamNo, AttrArg, + const AttrInfo &AI, unsigned AttrArgNo) { + assert(AI.isArgExpr(AttrArgNo) && "Expected expression argument"); + Expr *AttrArg = AI.getArgAsExpr(AttrArgNo); + ParamIdx Idx; + if (!checkFunctionOrMethodParameterIndex(S, FD, AI, AttrArgNo + 1, AttrArg, Idx)) return false; - const ParmVarDecl *Param = FD->getParamDecl(Idx); - if (AllowDependentType && Param->getType()->isDependentType()) - return true; + const ParmVarDecl *Param = FD->getParamDecl(Idx.getASTIndex()); if (!Param->getType()->isIntegerType() && !Param->getType()->isCharType()) { SourceLocation SrcLoc = AttrArg->getLocStart(); S.Diag(SrcLoc, diag::err_attribute_integers_only) - << getAttrName(Attr) << Param->getSourceRange(); + << getAttrName(AI) << Param->getSourceRange(); return false; } return true; } -/// \brief Checks to be sure that the given parameter number is in bounds, and is -/// an integral type. Will emit appropriate diagnostics if this returns false. -/// -/// FuncParamNo is expected to be from the user, so is base-1. AttrArgNo is used -/// to actually retrieve the argument, so it's base-0. -static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD, - const AttributeList &Attr, - unsigned FuncParamNo, unsigned AttrArgNo, - bool AllowDependentType = false) { - assert(Attr.isArgExpr(AttrArgNo) && "Expected expression argument"); - return checkParamIsIntegerType(S, FD, Attr, Attr.getArgAsExpr(AttrArgNo), - FuncParamNo, AttrArgNo, AllowDependentType); -} - -static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1) || - !checkAttributeAtMostNumArgs(S, Attr, 2)) +static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1) || + !checkAttributeAtMostNumArgs(S, AL, 2)) return; const auto *FD = cast<FunctionDecl>(D); if (!FD->getReturnType()->isPointerType()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_return_pointers_only) - << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) + << AL.getName(); return; } - const Expr *SizeExpr = Attr.getArgAsExpr(0); - int SizeArgNo; + const Expr *SizeExpr = AL.getArgAsExpr(0); + int SizeArgNoVal; // Parameter indices are 1-indexed, hence Index=1 - if (!checkPositiveIntArgument(S, Attr, SizeExpr, SizeArgNo, /*Index=*/1)) + if (!checkPositiveIntArgument(S, AL, SizeExpr, SizeArgNoVal, /*Index=*/1)) return; - - if (!checkParamIsIntegerType(S, FD, Attr, SizeArgNo, /*AttrArgNo=*/0)) + if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/0)) return; + ParamIdx SizeArgNo(SizeArgNoVal, D); - // Args are 1-indexed, so 0 implies that the arg was not present - int NumberArgNo = 0; - if (Attr.getNumArgs() == 2) { - const Expr *NumberExpr = Attr.getArgAsExpr(1); + ParamIdx NumberArgNo; + if (AL.getNumArgs() == 2) { + const Expr *NumberExpr = AL.getArgAsExpr(1); + int Val; // Parameter indices are 1-based, hence Index=2 - if (!checkPositiveIntArgument(S, Attr, NumberExpr, NumberArgNo, - /*Index=*/2)) + if (!checkPositiveIntArgument(S, AL, NumberExpr, Val, /*Index=*/2)) return; - - if (!checkParamIsIntegerType(S, FD, Attr, NumberArgNo, /*AttrArgNo=*/1)) + if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/1)) return; + NumberArgNo = ParamIdx(Val, D); } - D->addAttr(::new (S.Context) AllocSizeAttr( - Attr.getRange(), S.Context, SizeArgNo, NumberArgNo, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + AllocSizeAttr(AL.getRange(), S.Context, SizeArgNo, NumberArgNo, + AL.getAttributeSpellingListIndex())); } -static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, - const AttributeList &Attr, +static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, SmallVectorImpl<Expr *> &Args) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return false; - if (!isIntOrBool(Attr.getArgAsExpr(0))) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIntOrBool; + if (!isIntOrBool(AL.getArgAsExpr(0))) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 1 << AANT_ArgumentIntOrBool; return false; } // check that all arguments are lockable objects - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 1); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 1); return true; } static void handleSharedTrylockFunctionAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { SmallVector<Expr*, 2> Args; - if (!checkTryLockFunAttrCommon(S, D, Attr, Args)) + if (!checkTryLockFunAttrCommon(S, D, AL, Args)) return; - D->addAttr(::new (S.Context) - SharedTrylockFunctionAttr(Attr.getRange(), S.Context, - Attr.getArgAsExpr(0), - Args.data(), Args.size(), - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) SharedTrylockFunctionAttr( + AL.getRange(), S.Context, AL.getArgAsExpr(0), Args.data(), Args.size(), + AL.getAttributeSpellingListIndex())); } static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { SmallVector<Expr*, 2> Args; - if (!checkTryLockFunAttrCommon(S, D, Attr, Args)) + if (!checkTryLockFunAttrCommon(S, D, AL, Args)) return; D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr( - Attr.getRange(), S.Context, Attr.getArgAsExpr(0), Args.data(), - Args.size(), Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getArgAsExpr(0), Args.data(), + Args.size(), AL.getAttributeSpellingListIndex())); } -static void handleLockReturnedAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleLockReturnedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // check that the argument is lockable object SmallVector<Expr*, 1> Args; - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args); unsigned Size = Args.size(); if (Size == 0) return; D->addAttr(::new (S.Context) - LockReturnedAttr(Attr.getRange(), S.Context, Args[0], - Attr.getAttributeSpellingListIndex())); + LockReturnedAttr(AL.getRange(), S.Context, Args[0], + AL.getAttributeSpellingListIndex())); } -static void handleLocksExcludedAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) +static void handleLocksExcludedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; // check that all arguments are lockable objects SmallVector<Expr*, 1> Args; - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args); unsigned Size = Args.size(); if (Size == 0) return; Expr **StartArg = &Args[0]; D->addAttr(::new (S.Context) - LocksExcludedAttr(Attr.getRange(), S.Context, StartArg, Size, - Attr.getAttributeSpellingListIndex())); + LocksExcludedAttr(AL.getRange(), S.Context, StartArg, Size, + AL.getAttributeSpellingListIndex())); } -static bool checkFunctionConditionAttr(Sema &S, Decl *D, - const AttributeList &Attr, +static bool checkFunctionConditionAttr(Sema &S, Decl *D, const ParsedAttr &AL, Expr *&Cond, StringRef &Msg) { - Cond = Attr.getArgAsExpr(0); + Cond = AL.getArgAsExpr(0); if (!Cond->isTypeDependent()) { ExprResult Converted = S.PerformContextuallyConvertToBool(Cond); if (Converted.isInvalid()) @@ -941,7 +897,7 @@ static bool checkFunctionConditionAttr(Sema &S, Decl *D, Cond = Converted.get(); } - if (!S.checkStringLiteralArgumentAttr(Attr, 1, Msg)) + if (!S.checkStringLiteralArgumentAttr(AL, 1, Msg)) return false; if (Msg.empty()) @@ -951,8 +907,8 @@ static bool checkFunctionConditionAttr(Sema &S, Decl *D, if (isa<FunctionDecl>(D) && !Cond->isValueDependent() && !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(D), Diags)) { - S.Diag(Attr.getLoc(), diag::err_attr_cond_never_constant_expr) - << Attr.getName(); + S.Diag(AL.getLoc(), diag::err_attr_cond_never_constant_expr) + << AL.getName(); for (const PartialDiagnosticAt &PDiag : Diags) S.Diag(PDiag.first, PDiag.second); return false; @@ -960,15 +916,15 @@ static bool checkFunctionConditionAttr(Sema &S, Decl *D, return true; } -static void handleEnableIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { - S.Diag(Attr.getLoc(), diag::ext_clang_enable_if); +static void handleEnableIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + S.Diag(AL.getLoc(), diag::ext_clang_enable_if); Expr *Cond; StringRef Msg; - if (checkFunctionConditionAttr(S, D, Attr, Cond, Msg)) + if (checkFunctionConditionAttr(S, D, AL, Cond, Msg)) D->addAttr(::new (S.Context) - EnableIfAttr(Attr.getRange(), S.Context, Cond, Msg, - Attr.getAttributeSpellingListIndex())); + EnableIfAttr(AL.getRange(), S.Context, Cond, Msg, + AL.getAttributeSpellingListIndex())); } namespace { @@ -1017,21 +973,21 @@ public: }; } -static void handleDiagnoseIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { - S.Diag(Attr.getLoc(), diag::ext_clang_diagnose_if); +static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + S.Diag(AL.getLoc(), diag::ext_clang_diagnose_if); Expr *Cond; StringRef Msg; - if (!checkFunctionConditionAttr(S, D, Attr, Cond, Msg)) + if (!checkFunctionConditionAttr(S, D, AL, Cond, Msg)) return; StringRef DiagTypeStr; - if (!S.checkStringLiteralArgumentAttr(Attr, 2, DiagTypeStr)) + if (!S.checkStringLiteralArgumentAttr(AL, 2, DiagTypeStr)) return; DiagnoseIfAttr::DiagnosticType DiagType; if (!DiagnoseIfAttr::ConvertStrToDiagnosticType(DiagTypeStr, DiagType)) { - S.Diag(Attr.getArgAsExpr(2)->getLocStart(), + S.Diag(AL.getArgAsExpr(2)->getLocStart(), diag::err_diagnose_if_invalid_diagnostic_type); return; } @@ -1040,21 +996,20 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (const auto *FD = dyn_cast<FunctionDecl>(D)) ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond); D->addAttr(::new (S.Context) DiagnoseIfAttr( - Attr.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D), - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, + cast<NamedDecl>(D), AL.getAttributeSpellingListIndex())); } -static void handlePassObjectSizeAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->hasAttr<PassObjectSizeAttr>()) { S.Diag(D->getLocStart(), diag::err_attribute_only_once_per_parameter) - << Attr.getName(); + << AL.getName(); return; } - Expr *E = Attr.getArgAsExpr(0); + Expr *E = AL.getArgAsExpr(0); uint32_t Type; - if (!checkUInt32Argument(S, Attr, E, Type, /*Idx=*/1)) + if (!checkUInt32Argument(S, AL, E, Type, /*Idx=*/1)) return; // pass_object_size's argument is passed in as the second argument of @@ -1062,7 +1017,7 @@ static void handlePassObjectSizeAttr(Sema &S, Decl *D, // argument; namely, it must be in the range [0, 3]. if (Type > 3) { S.Diag(E->getLocStart(), diag::err_attribute_argument_outof_range) - << Attr.getName() << 0 << 3 << E->getSourceRange(); + << AL.getName() << 0 << 3 << E->getSourceRange(); return; } @@ -1072,112 +1027,109 @@ static void handlePassObjectSizeAttr(Sema &S, Decl *D, // definition, so we defer the constness check until later. if (!cast<ParmVarDecl>(D)->getType()->isPointerType()) { S.Diag(D->getLocStart(), diag::err_attribute_pointers_only) - << Attr.getName() << 1; + << AL.getName() << 1; return; } - D->addAttr(::new (S.Context) - PassObjectSizeAttr(Attr.getRange(), S.Context, (int)Type, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) PassObjectSizeAttr( + AL.getRange(), S.Context, (int)Type, AL.getAttributeSpellingListIndex())); } -static void handleConsumableAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleConsumableAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ConsumableAttr::ConsumedState DefaultState; - if (Attr.isArgIdent(0)) { - IdentifierLoc *IL = Attr.getArgAsIdent(0); + if (AL.isArgIdent(0)) { + IdentifierLoc *IL = AL.getArgAsIdent(0); if (!ConsumableAttr::ConvertStrToConsumedState(IL->Ident->getName(), DefaultState)) { S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << IL->Ident; + << AL.getName() << IL->Ident; return; } } else { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL.getName() << AANT_ArgumentIdentifier; return; } - + D->addAttr(::new (S.Context) - ConsumableAttr(Attr.getRange(), S.Context, DefaultState, - Attr.getAttributeSpellingListIndex())); + ConsumableAttr(AL.getRange(), S.Context, DefaultState, + AL.getAttributeSpellingListIndex())); } static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD, - const AttributeList &Attr) { + const ParsedAttr &AL) { ASTContext &CurrContext = S.getASTContext(); QualType ThisType = MD->getThisType(CurrContext)->getPointeeType(); - + if (const CXXRecordDecl *RD = ThisType->getAsCXXRecordDecl()) { if (!RD->hasAttr<ConsumableAttr>()) { - S.Diag(Attr.getLoc(), diag::warn_attr_on_unconsumable_class) << + S.Diag(AL.getLoc(), diag::warn_attr_on_unconsumable_class) << RD->getNameAsString(); - + return false; } } - + return true; } -static void handleCallableWhenAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) +static void handleCallableWhenAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; - - if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) + + if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL)) return; - + SmallVector<CallableWhenAttr::ConsumedState, 3> States; - for (unsigned ArgIndex = 0; ArgIndex < Attr.getNumArgs(); ++ArgIndex) { + for (unsigned ArgIndex = 0; ArgIndex < AL.getNumArgs(); ++ArgIndex) { CallableWhenAttr::ConsumedState CallableState; - + StringRef StateString; SourceLocation Loc; - if (Attr.isArgIdent(ArgIndex)) { - IdentifierLoc *Ident = Attr.getArgAsIdent(ArgIndex); + if (AL.isArgIdent(ArgIndex)) { + IdentifierLoc *Ident = AL.getArgAsIdent(ArgIndex); StateString = Ident->Ident->getName(); Loc = Ident->Loc; } else { - if (!S.checkStringLiteralArgumentAttr(Attr, ArgIndex, StateString, &Loc)) + if (!S.checkStringLiteralArgumentAttr(AL, ArgIndex, StateString, &Loc)) return; } if (!CallableWhenAttr::ConvertStrToConsumedState(StateString, CallableState)) { S.Diag(Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << StateString; + << AL.getName() << StateString; return; } - + States.push_back(CallableState); } - + D->addAttr(::new (S.Context) - CallableWhenAttr(Attr.getRange(), S.Context, States.data(), - States.size(), Attr.getAttributeSpellingListIndex())); + CallableWhenAttr(AL.getRange(), S.Context, States.data(), + States.size(), AL.getAttributeSpellingListIndex())); } -static void handleParamTypestateAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleParamTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ParamTypestateAttr::ConsumedState ParamState; - - if (Attr.isArgIdent(0)) { - IdentifierLoc *Ident = Attr.getArgAsIdent(0); + + if (AL.isArgIdent(0)) { + IdentifierLoc *Ident = AL.getArgAsIdent(0); StringRef StateString = Ident->Ident->getName(); if (!ParamTypestateAttr::ConvertStrToConsumedState(StateString, ParamState)) { S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << StateString; + << AL.getName() << StateString; return; } } else { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << - Attr.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << + AL.getName() << AANT_ArgumentIdentifier; return; } - + // FIXME: This check is currently being done in the analysis. It can be // enabled here only after the parser propagates attributes at // template specialization definition, not declaration. @@ -1185,34 +1137,33 @@ static void handleParamTypestateAttr(Sema &S, Decl *D, //const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl(); // //if (!RD || !RD->hasAttr<ConsumableAttr>()) { - // S.Diag(Attr.getLoc(), diag::warn_return_state_for_unconsumable_type) << + // S.Diag(AL.getLoc(), diag::warn_return_state_for_unconsumable_type) << // ReturnType.getAsString(); // return; //} - + D->addAttr(::new (S.Context) - ParamTypestateAttr(Attr.getRange(), S.Context, ParamState, - Attr.getAttributeSpellingListIndex())); + ParamTypestateAttr(AL.getRange(), S.Context, ParamState, + AL.getAttributeSpellingListIndex())); } -static void handleReturnTypestateAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleReturnTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ReturnTypestateAttr::ConsumedState ReturnState; - - if (Attr.isArgIdent(0)) { - IdentifierLoc *IL = Attr.getArgAsIdent(0); + + if (AL.isArgIdent(0)) { + IdentifierLoc *IL = AL.getArgAsIdent(0); if (!ReturnTypestateAttr::ConvertStrToConsumedState(IL->Ident->getName(), ReturnState)) { S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << IL->Ident; + << AL.getName() << IL->Ident; return; } } else { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << - Attr.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << + AL.getName() << AANT_ArgumentIdentifier; return; } - + // FIXME: This check is currently being done in the analysis. It can be // enabled here only after the parser propagates attributes at // template specialization definition, not declaration. @@ -1224,9 +1175,9 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, //} else if (const CXXConstructorDecl *Constructor = // dyn_cast<CXXConstructorDecl>(D)) { // ReturnType = Constructor->getThisType(S.getASTContext())->getPointeeType(); - // + // //} else { - // + // // ReturnType = cast<FunctionDecl>(D)->getCallResultType(); //} // @@ -1237,72 +1188,70 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, // ReturnType.getAsString(); // return; //} - + D->addAttr(::new (S.Context) - ReturnTypestateAttr(Attr.getRange(), S.Context, ReturnState, - Attr.getAttributeSpellingListIndex())); + ReturnTypestateAttr(AL.getRange(), S.Context, ReturnState, + AL.getAttributeSpellingListIndex())); } -static void handleSetTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) +static void handleSetTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL)) return; - + SetTypestateAttr::ConsumedState NewState; - if (Attr.isArgIdent(0)) { - IdentifierLoc *Ident = Attr.getArgAsIdent(0); + if (AL.isArgIdent(0)) { + IdentifierLoc *Ident = AL.getArgAsIdent(0); StringRef Param = Ident->Ident->getName(); if (!SetTypestateAttr::ConvertStrToConsumedState(Param, NewState)) { S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << Param; + << AL.getName() << Param; return; } } else { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << - Attr.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << + AL.getName() << AANT_ArgumentIdentifier; return; } - + D->addAttr(::new (S.Context) - SetTypestateAttr(Attr.getRange(), S.Context, NewState, - Attr.getAttributeSpellingListIndex())); + SetTypestateAttr(AL.getRange(), S.Context, NewState, + AL.getAttributeSpellingListIndex())); } -static void handleTestTypestateAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) +static void handleTestTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL)) return; - - TestTypestateAttr::ConsumedState TestState; - if (Attr.isArgIdent(0)) { - IdentifierLoc *Ident = Attr.getArgAsIdent(0); + + TestTypestateAttr::ConsumedState TestState; + if (AL.isArgIdent(0)) { + IdentifierLoc *Ident = AL.getArgAsIdent(0); StringRef Param = Ident->Ident->getName(); if (!TestTypestateAttr::ConvertStrToConsumedState(Param, TestState)) { S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << Param; + << AL.getName() << Param; return; } } else { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << - Attr.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << + AL.getName() << AANT_ArgumentIdentifier; return; } - + D->addAttr(::new (S.Context) - TestTypestateAttr(Attr.getRange(), S.Context, TestState, - Attr.getAttributeSpellingListIndex())); + TestTypestateAttr(AL.getRange(), S.Context, TestState, + AL.getAttributeSpellingListIndex())); } -static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D, - const AttributeList &Attr) { +static void handleExtVectorTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Remember this typedef decl, we will need it later for diagnostics. S.ExtVectorDecls.push_back(cast<TypedefNameDecl>(D)); } -static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (TagDecl *TD = dyn_cast<TagDecl>(D)) - TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { +static void handlePackedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (auto *TD = dyn_cast<TagDecl>(D)) + TD->addAttr(::new (S.Context) PackedAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); + else if (auto *FD = dyn_cast<FieldDecl>(D)) { bool BitfieldByteAligned = (!FD->getType()->isDependentType() && !FD->getType()->isIncompleteType() && FD->isBitField() && @@ -1311,81 +1260,80 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (S.getASTContext().getTargetInfo().getTriple().isPS4()) { if (BitfieldByteAligned) // The PS4 target needs to maintain ABI backwards compatibility. - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type) - << Attr.getName() << FD->getType(); + S.Diag(AL.getLoc(), diag::warn_attribute_ignored_for_field_of_type) + << AL.getName() << FD->getType(); else FD->addAttr(::new (S.Context) PackedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } else { // Report warning about changed offset in the newer compiler versions. if (BitfieldByteAligned) - S.Diag(Attr.getLoc(), diag::warn_attribute_packed_for_bitfield); + S.Diag(AL.getLoc(), diag::warn_attribute_packed_for_bitfield); FD->addAttr(::new (S.Context) PackedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } } else - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL.getName(); } -static bool checkIBOutletCommon(Sema &S, Decl *D, const AttributeList &Attr) { +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 ObjCIvarDecl *VD = dyn_cast<ObjCIvarDecl>(D)) { + if (const auto *VD = dyn_cast<ObjCIvarDecl>(D)) { if (!VD->getType()->getAs<ObjCObjectPointerType>()) { - S.Diag(Attr.getLoc(), diag::warn_iboutlet_object_type) - << Attr.getName() << VD->getType() << 0; + S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type) + << AL.getName() << VD->getType() << 0; return false; } } - else if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) { + else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) { if (!PD->getType()->getAs<ObjCObjectPointerType>()) { - S.Diag(Attr.getLoc(), diag::warn_iboutlet_object_type) - << Attr.getName() << PD->getType() << 1; + S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type) + << AL.getName() << PD->getType() << 1; return false; } } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_iboutlet) << AL.getName(); return false; } return true; } -static void handleIBOutlet(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkIBOutletCommon(S, D, Attr)) +static void handleIBOutlet(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkIBOutletCommon(S, D, AL)) return; D->addAttr(::new (S.Context) - IBOutletAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + IBOutletAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleIBOutletCollection(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleIBOutletCollection(Sema &S, Decl *D, const ParsedAttr &AL) { // The iboutletcollection attribute can have zero or one arguments. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 1; + if (AL.getNumArgs() > 1) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) + << AL.getName() << 1; return; } - if (!checkIBOutletCommon(S, D, Attr)) + if (!checkIBOutletCommon(S, D, AL)) return; ParsedType PT; - if (Attr.hasParsedType()) - PT = Attr.getTypeArg(); + if (AL.hasParsedType()) + PT = AL.getTypeArg(); else { - PT = S.getTypeName(S.Context.Idents.get("NSObject"), Attr.getLoc(), + PT = S.getTypeName(S.Context.Idents.get("NSObject"), AL.getLoc(), S.getScopeForContext(D->getDeclContext()->getParent())); if (!PT) { - S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << "NSObject"; + S.Diag(AL.getLoc(), diag::err_iboutletcollection_type) << "NSObject"; return; } } @@ -1393,22 +1341,22 @@ static void handleIBOutletCollection(Sema &S, Decl *D, TypeSourceInfo *QTLoc = nullptr; QualType QT = S.GetTypeFromParser(PT, &QTLoc); if (!QTLoc) - QTLoc = S.Context.getTrivialTypeSourceInfo(QT, Attr.getLoc()); + 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(Attr.getLoc(), + S.Diag(AL.getLoc(), QT->isBuiltinType() ? diag::err_iboutletcollection_builtintype : diag::err_iboutletcollection_type) << QT; return; } D->addAttr(::new (S.Context) - IBOutletCollectionAttr(Attr.getRange(), S.Context, QTLoc, - Attr.getAttributeSpellingListIndex())); + IBOutletCollectionAttr(AL.getRange(), S.Context, QTLoc, + AL.getAttributeSpellingListIndex())); } bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) { @@ -1435,35 +1383,36 @@ bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) { return T->isAnyPointerType() || T->isBlockPointerType(); } -static bool attrNonNullArgCheck(Sema &S, QualType T, const AttributeList &Attr, +static bool attrNonNullArgCheck(Sema &S, QualType T, const ParsedAttr &AL, SourceRange AttrParmRange, SourceRange TypeRange, bool isReturnValue = false) { if (!S.isValidPointerAttrType(T)) { if (isReturnValue) - S.Diag(Attr.getLoc(), diag::warn_attribute_return_pointers_only) - << Attr.getName() << AttrParmRange << TypeRange; + S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) + << AL.getName() << AttrParmRange << TypeRange; else - S.Diag(Attr.getLoc(), diag::warn_attribute_pointers_only) - << Attr.getName() << AttrParmRange << TypeRange << 0; + S.Diag(AL.getLoc(), diag::warn_attribute_pointers_only) + << AL.getName() << AttrParmRange << TypeRange << 0; return false; } return true; } -static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { - SmallVector<unsigned, 8> NonNullArgs; - for (unsigned I = 0; I < Attr.getNumArgs(); ++I) { - Expr *Ex = Attr.getArgAsExpr(I); - uint64_t Idx; - if (!checkFunctionOrMethodParameterIndex(S, D, Attr, I + 1, Ex, Idx)) +static void handleNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + SmallVector<ParamIdx, 8> NonNullArgs; + for (unsigned I = 0; I < AL.getNumArgs(); ++I) { + Expr *Ex = AL.getArgAsExpr(I); + ParamIdx Idx; + if (!checkFunctionOrMethodParameterIndex(S, D, AL, I + 1, Ex, Idx)) return; // Is the function argument a pointer type? - if (Idx < getFunctionOrMethodNumParams(D) && - !attrNonNullArgCheck(S, getFunctionOrMethodParamType(D, Idx), Attr, - Ex->getSourceRange(), - getFunctionOrMethodParamRange(D, Idx))) + if (Idx.getASTIndex() < getFunctionOrMethodNumParams(D) && + !attrNonNullArgCheck( + S, getFunctionOrMethodParamType(D, Idx.getASTIndex()), AL, + Ex->getSourceRange(), + getFunctionOrMethodParamRange(D, Idx.getASTIndex()))) continue; NonNullArgs.push_back(Idx); @@ -1473,7 +1422,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { // arguments have a nonnull attribute; warn if there aren't any. Skip this // check if the attribute came from a macro expansion or a template // instantiation. - if (NonNullArgs.empty() && Attr.getLoc().isFileID() && + if (NonNullArgs.empty() && AL.getLoc().isFileID() && !S.inTemplateInstantiation()) { bool AnyPointers = isFunctionOrMethodVariadic(D); for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); @@ -1484,80 +1433,77 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { } if (!AnyPointers) - S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers); + S.Diag(AL.getLoc(), diag::warn_attribute_nonnull_no_pointers); } - unsigned *Start = NonNullArgs.data(); + ParamIdx *Start = NonNullArgs.data(); unsigned Size = NonNullArgs.size(); llvm::array_pod_sort(Start, Start + Size); D->addAttr(::new (S.Context) - NonNullAttr(Attr.getRange(), S.Context, Start, Size, - Attr.getAttributeSpellingListIndex())); + NonNullAttr(AL.getRange(), S.Context, Start, Size, + AL.getAttributeSpellingListIndex())); } static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D, - const AttributeList &Attr) { - if (Attr.getNumArgs() > 0) { + const ParsedAttr &AL) { + if (AL.getNumArgs() > 0) { if (D->getFunctionType()) { - handleNonNullAttr(S, D, Attr); + handleNonNullAttr(S, D, AL); } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_parm_no_args) + S.Diag(AL.getLoc(), diag::warn_attribute_nonnull_parm_no_args) << D->getSourceRange(); } return; } // Is the argument a pointer type? - if (!attrNonNullArgCheck(S, D->getType(), Attr, SourceRange(), + if (!attrNonNullArgCheck(S, D->getType(), AL, SourceRange(), D->getSourceRange())) return; D->addAttr(::new (S.Context) - NonNullAttr(Attr.getRange(), S.Context, nullptr, 0, - Attr.getAttributeSpellingListIndex())); + NonNullAttr(AL.getRange(), S.Context, nullptr, 0, + AL.getAttributeSpellingListIndex())); } -static void handleReturnsNonNullAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleReturnsNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) { QualType ResultType = getFunctionOrMethodResultType(D); SourceRange SR = getFunctionOrMethodResultSourceRange(D); - if (!attrNonNullArgCheck(S, ResultType, Attr, SourceRange(), SR, + if (!attrNonNullArgCheck(S, ResultType, AL, SourceRange(), SR, /* isReturnValue */ true)) return; D->addAttr(::new (S.Context) - ReturnsNonNullAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ReturnsNonNullAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleNoEscapeAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleNoEscapeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->isInvalidDecl()) return; // noescape only applies to pointer types. QualType T = cast<ParmVarDecl>(D)->getType(); if (!S.isValidPointerAttrType(T, /* RefOkay */ true)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_pointers_only) - << Attr.getName() << Attr.getRange() << 0; + S.Diag(AL.getLoc(), diag::warn_attribute_pointers_only) + << AL.getName() << AL.getRange() << 0; return; } D->addAttr(::new (S.Context) NoEscapeAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } -static void handleAssumeAlignedAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - Expr *E = Attr.getArgAsExpr(0), - *OE = Attr.getNumArgs() > 1 ? Attr.getArgAsExpr(1) : nullptr; - S.AddAssumeAlignedAttr(Attr.getRange(), D, E, OE, - Attr.getAttributeSpellingListIndex()); +static void handleAssumeAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + Expr *E = AL.getArgAsExpr(0), + *OE = AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr; + S.AddAssumeAlignedAttr(AL.getRange(), D, E, OE, + AL.getAttributeSpellingListIndex()); } -static void handleAllocAlignAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - S.AddAllocAlignAttr(Attr.getRange(), D, Attr.getArgAsExpr(0), - Attr.getAttributeSpellingListIndex()); +static void handleAllocAlignAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + S.AddAllocAlignAttr(AL.getRange(), D, AL.getArgAsExpr(0), + AL.getAttributeSpellingListIndex()); } void Sema::AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, @@ -1615,7 +1561,7 @@ void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr, unsigned SpellingListIndex) { QualType ResultType = getFunctionOrMethodResultType(D); - AllocAlignAttr TmpAttr(AttrRange, Context, 0, SpellingListIndex); + AllocAlignAttr TmpAttr(AttrRange, Context, ParamIdx(), SpellingListIndex); SourceLocation AttrLoc = AttrRange.getBegin(); if (!ResultType->isDependentType() && @@ -1625,28 +1571,22 @@ void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr, return; } - uint64_t IndexVal; + ParamIdx Idx; const auto *FuncDecl = cast<FunctionDecl>(D); if (!checkFunctionOrMethodParameterIndex(*this, FuncDecl, TmpAttr, - /*AttrArgNo=*/1, ParamExpr, - IndexVal)) + /*AttrArgNo=*/1, ParamExpr, Idx)) return; - QualType Ty = getFunctionOrMethodParamType(D, IndexVal); + QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex()); if (!Ty->isDependentType() && !Ty->isIntegralType(Context)) { Diag(ParamExpr->getLocStart(), diag::err_attribute_integers_only) - << &TmpAttr << FuncDecl->getParamDecl(IndexVal)->getSourceRange(); + << &TmpAttr + << FuncDecl->getParamDecl(Idx.getASTIndex())->getSourceRange(); return; } - // We cannot use the Idx returned from checkFunctionOrMethodParameterIndex - // because that has corrected for the implicit this parameter, and is zero- - // based. The attribute expects what the user wrote explicitly. - llvm::APSInt Val; - ParamExpr->EvaluateAsInt(Val, Context); - - D->addAttr(::new (Context) AllocAlignAttr( - AttrRange, Context, Val.getZExtValue(), SpellingListIndex)); + D->addAttr(::new (Context) + AllocAlignAttr(AttrRange, Context, Idx, SpellingListIndex)); } /// Normalize the attribute, __foo__ becomes foo. @@ -1660,7 +1600,7 @@ static bool normalizeName(StringRef &AttrName) { return false; } -static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { +static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // This attribute must be applied to a function declaration. The first // argument to the attribute must be an identifier, the name of the resource, // for example: malloc. The following arguments must be argument indexes, the @@ -1706,15 +1646,15 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { Module = &S.PP.getIdentifierTable().get(ModuleName); } - SmallVector<unsigned, 8> OwnershipArgs; + SmallVector<ParamIdx, 8> OwnershipArgs; for (unsigned i = 1; i < AL.getNumArgs(); ++i) { Expr *Ex = AL.getArgAsExpr(i); - uint64_t Idx; + ParamIdx Idx; if (!checkFunctionOrMethodParameterIndex(S, D, AL, i, Ex, Idx)) return; // Is the function argument a pointer type? - QualType T = getFunctionOrMethodParamType(D, Idx); + QualType T = getFunctionOrMethodParamType(D, Idx.getASTIndex()); int Err = -1; // No error switch (K) { case OwnershipAttr::Takes: @@ -1745,14 +1685,13 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { } else if (K == OwnershipAttr::Returns && I->getOwnKind() == OwnershipAttr::Returns) { // A returns attribute conflicts with any other returns attribute using - // a different index. Note, diagnostic reporting is 1-based, but stored - // argument indexes are 0-based. + // a different index. if (std::find(I->args_begin(), I->args_end(), Idx) == I->args_end()) { S.Diag(I->getLocation(), diag::err_ownership_returns_index_mismatch) - << *(I->args_begin()) + 1; + << I->args_begin()->getSourceIndex(); if (I->args_size()) S.Diag(AL.getLoc(), diag::note_ownership_returns_index_mismatch) - << (unsigned)Idx + 1 << Ex->getSourceRange(); + << Idx.getSourceIndex() << Ex->getSourceRange(); return; } } @@ -1760,25 +1699,22 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { OwnershipArgs.push_back(Idx); } - unsigned* start = OwnershipArgs.data(); - unsigned size = OwnershipArgs.size(); - llvm::array_pod_sort(start, start + size); - + ParamIdx *Start = OwnershipArgs.data(); + unsigned Size = OwnershipArgs.size(); + llvm::array_pod_sort(Start, Start + Size); D->addAttr(::new (S.Context) - OwnershipAttr(AL.getLoc(), S.Context, Module, start, size, - AL.getAttributeSpellingListIndex())); + OwnershipAttr(AL.getLoc(), S.Context, Module, Start, Size, + AL.getAttributeSpellingListIndex())); } -static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Check the attribute arguments. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 1; + if (AL.getNumArgs() > 1) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) + << AL.getName() << 1; return; } - NamedDecl *nd = cast<NamedDecl>(D); - // gcc rejects // class c { // static int a __attribute__((weakref ("v2"))); @@ -1791,8 +1727,8 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) { // we reject them const DeclContext *Ctx = D->getDeclContext()->getRedeclContext(); if (!Ctx->isFileContext()) { - S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context) - << nd; + S.Diag(AL.getLoc(), diag::err_attribute_weakref_not_global_context) + << cast<NamedDecl>(D); return; } @@ -1822,88 +1758,71 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) { // of transforming it into an AliasAttr. The WeakRefAttr never uses the // StringRef parameter it was given anyway. StringRef Str; - if (Attr.getNumArgs() && S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (AL.getNumArgs() && S.checkStringLiteralArgumentAttr(AL, 0, Str)) // GCC will accept anything as the argument of weakref. Should we // check for an existing decl? - D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context, Str, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AliasAttr(AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); D->addAttr(::new (S.Context) - WeakRefAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + WeakRefAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleIFuncAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Str; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; // Aliases should be on declarations, not definitions. const auto *FD = cast<FunctionDecl>(D); if (FD->isThisDeclarationADefinition()) { - S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD << 1; + S.Diag(AL.getLoc(), diag::err_alias_is_definition) << FD << 1; return; } - D->addAttr(::new (S.Context) IFuncAttr(Attr.getRange(), S.Context, Str, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) IFuncAttr(AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); } -static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Str; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; if (S.Context.getTargetInfo().getTriple().isOSDarwin()) { - S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_darwin); + S.Diag(AL.getLoc(), diag::err_alias_not_supported_on_darwin); return; } if (S.Context.getTargetInfo().getTriple().isNVPTX()) { - S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_nvptx); + S.Diag(AL.getLoc(), diag::err_alias_not_supported_on_nvptx); } // Aliases should be on declarations, not definitions. if (const auto *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isThisDeclarationADefinition()) { - S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD << 0; + S.Diag(AL.getLoc(), diag::err_alias_is_definition) << FD << 0; return; } } else { const auto *VD = cast<VarDecl>(D); if (VD->isThisDeclarationADefinition() && VD->isExternallyVisible()) { - S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << VD << 0; + S.Diag(AL.getLoc(), diag::err_alias_is_definition) << VD << 0; return; } } // FIXME: check if target symbol exists in current file - D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context, Str, - Attr.getAttributeSpellingListIndex())); -} - -static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<HotAttr>(S, D, Attr.getRange(), Attr.getName())) - return; - - D->addAttr(::new (S.Context) ColdAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AliasAttr(AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); } -static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<ColdAttr>(S, D, Attr.getRange(), Attr.getName())) - return; - - D->addAttr(::new (S.Context) HotAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleTLSModelAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleTLSModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Model; SourceLocation LiteralLoc; // Check that it is a string. - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Model, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Model, &LiteralLoc)) return; // Check that the value. @@ -1914,60 +1833,101 @@ static void handleTLSModelAttr(Sema &S, Decl *D, } D->addAttr(::new (S.Context) - TLSModelAttr(Attr.getRange(), S.Context, Model, - Attr.getAttributeSpellingListIndex())); + TLSModelAttr(AL.getRange(), S.Context, Model, + AL.getAttributeSpellingListIndex())); } -static void handleRestrictAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) { QualType ResultType = getFunctionOrMethodResultType(D); if (ResultType->isAnyPointerType() || ResultType->isBlockPointerType()) { D->addAttr(::new (S.Context) RestrictAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; } - S.Diag(Attr.getLoc(), diag::warn_attribute_return_pointers_only) - << Attr.getName() << getFunctionOrMethodResultSourceRange(D); + S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) + << AL.getName() << getFunctionOrMethodResultSourceRange(D); +} + +static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + FunctionDecl *FD = cast<FunctionDecl>(D); + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) + return; + + SmallVector<IdentifierInfo *, 8> CPUs; + for (unsigned ArgNo = 0; ArgNo < getNumAttributeArgs(AL); ++ArgNo) { + if (!AL.isArgIdent(ArgNo)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL.getName() << AANT_ArgumentIdentifier; + return; + } + + IdentifierLoc *CPUArg = AL.getArgAsIdent(ArgNo); + StringRef CPUName = CPUArg->Ident->getName().trim(); + + if (!S.Context.getTargetInfo().validateCPUSpecificCPUDispatch(CPUName)) { + S.Diag(CPUArg->Loc, diag::err_invalid_cpu_specific_dispatch_value) + << CPUName << (AL.getKind() == ParsedAttr::AT_CPUDispatch); + return; + } + + const TargetInfo &Target = S.Context.getTargetInfo(); + if (llvm::any_of(CPUs, [CPUName, &Target](const IdentifierInfo *Cur) { + return Target.CPUSpecificManglingCharacter(CPUName) == + Target.CPUSpecificManglingCharacter(Cur->getName()); + })) { + S.Diag(AL.getLoc(), diag::warn_multiversion_duplicate_entries); + return; + } + CPUs.push_back(CPUArg->Ident); + } + + FD->setIsMultiVersion(true); + if (AL.getKind() == ParsedAttr::AT_CPUSpecific) + D->addAttr(::new (S.Context) CPUSpecificAttr( + AL.getRange(), S.Context, CPUs.data(), CPUs.size(), + AL.getAttributeSpellingListIndex())); + else + D->addAttr(::new (S.Context) CPUDispatchAttr( + AL.getRange(), S.Context, CPUs.data(), CPUs.size(), + AL.getAttributeSpellingListIndex())); } -static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleCommonAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (S.LangOpts.CPlusPlus) { - S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang) - << Attr.getName() << AttributeLangSupport::Cpp; + S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) + << AL.getName() << AttributeLangSupport::Cpp; return; } - if (CommonAttr *CA = S.mergeCommonAttr(D, Attr.getRange(), Attr.getName(), - Attr.getAttributeSpellingListIndex())) + if (CommonAttr *CA = S.mergeCommonAttr(D, AL.getRange(), AL.getName(), + AL.getAttributeSpellingListIndex())) D->addAttr(CA); } -static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<DisableTailCallsAttr>(S, D, Attr.getRange(), - Attr.getName())) +static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<DisableTailCallsAttr>(S, D, AL.getRange(), + AL.getName())) return; - if (Attr.isDeclspecAttribute()) { + if (AL.isDeclspecAttribute()) { const auto &Triple = S.getASTContext().getTargetInfo().getTriple(); const auto &Arch = Triple.getArch(); if (Arch != llvm::Triple::x86 && (Arch != llvm::Triple::arm && Arch != llvm::Triple::thumb)) { - S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_on_arch) - << Attr.getName() << Triple.getArchName(); + S.Diag(AL.getLoc(), diag::err_attribute_not_supported_on_arch) + << AL.getName() << Triple.getArchName(); return; } } - D->addAttr(::new (S.Context) NakedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) NakedAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &Attrs) { +static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) { if (hasDeclarator(D)) return; - if (S.CheckNoReturnAttr(Attrs)) - return; - if (!isa<ObjCMethodDecl>(D)) { S.Diag(Attrs.getLoc(), diag::warn_attribute_wrong_decl_type) << Attrs.getName() << ExpectedFunctionOrMethod; @@ -1978,16 +1938,14 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &Attrs) { Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex())); } -static void handleNoCallerSavedRegsAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (S.CheckNoCallerSavedRegsAttr(Attr)) - return; - - D->addAttr(::new (S.Context) AnyX86NoCallerSavedRegistersAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); +static void handleNoCfCheckAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) { + if (!S.getLangOpts().CFProtectionBranch) + S.Diag(Attrs.getLoc(), diag::warn_nocf_check_attribute_ignored); + else + handleSimpleAttribute<AnyX86NoCfCheckAttr>(S, D, Attrs); } -bool Sema::CheckNoReturnAttr(const AttributeList &Attrs) { +bool Sema::CheckAttrNoArgs(const ParsedAttr &Attrs) { if (!checkAttributeNumArgs(*this, Attrs, 0)) { Attrs.setInvalid(); return true; @@ -1996,221 +1954,167 @@ bool Sema::CheckNoReturnAttr(const AttributeList &Attrs) { return false; } -bool Sema::CheckNoCallerSavedRegsAttr(const AttributeList &Attr) { +bool Sema::CheckAttrTarget(const ParsedAttr &AL) { // Check whether the attribute is valid on the current target. - if (!Attr.existsInTarget(Context.getTargetInfo())) { - Diag(Attr.getLoc(), diag::warn_unknown_attribute_ignored) << Attr.getName(); - Attr.setInvalid(); - return true; - } - - if (!checkAttributeNumArgs(*this, Attr, 0)) { - Attr.setInvalid(); + if (!AL.existsInTarget(Context.getTargetInfo())) { + Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL.getName(); + AL.setInvalid(); return true; } return false; } -static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - +static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // The checking path for 'noreturn' and 'analyzer_noreturn' are different // because 'analyzer_noreturn' does not impact the type. if (!isFunctionOrMethodOrBlock(D)) { ValueDecl *VD = dyn_cast<ValueDecl>(D); if (!VD || (!VD->getType()->isBlockPointerType() && !VD->getType()->isFunctionPointerType())) { - S.Diag(Attr.getLoc(), - Attr.isCXX11Attribute() ? diag::err_attribute_wrong_decl_type + S.Diag(AL.getLoc(), + AL.isCXX11Attribute() ? diag::err_attribute_wrong_decl_type : diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionMethodOrBlock; + << AL.getName() << ExpectedFunctionMethodOrBlock; return; } } - + D->addAttr(::new (S.Context) - AnalyzerNoReturnAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + AnalyzerNoReturnAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } // PS3 PPU-specific. -static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) { -/* - Returning a Vector Class in Registers - - According to the PPU ABI specifications, a class with a single member of - vector type is returned in memory when used as the return value of a function. - This results in inefficient code when implementing vector classes. To return - the value in a single vector register, add the vecreturn attribute to the - class definition. This attribute is also applicable to struct types. - - Example: - - struct Vector - { - __vector float xyzw; - } __attribute__((vecreturn)); - - Vector Add(Vector lhs, Vector rhs) - { - Vector result; - result.xyzw = vec_add(lhs.xyzw, rhs.xyzw); - return result; // This will be returned in a register - } -*/ +static void handleVecReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + /* + Returning a Vector Class in Registers + + According to the PPU ABI specifications, a class with a single member of + vector type is returned in memory when used as the return value of a + function. + This results in inefficient code when implementing vector classes. To return + the value in a single vector register, add the vecreturn attribute to the + class definition. This attribute is also applicable to struct types. + + Example: + + struct Vector + { + __vector float xyzw; + } __attribute__((vecreturn)); + + Vector Add(Vector lhs, Vector rhs) + { + Vector result; + result.xyzw = vec_add(lhs.xyzw, rhs.xyzw); + return result; // This will be returned in a register + } + */ if (VecReturnAttr *A = D->getAttr<VecReturnAttr>()) { - S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << A; + S.Diag(AL.getLoc(), diag::err_repeat_attribute) << A; return; } - RecordDecl *record = cast<RecordDecl>(D); + const auto *R = cast<RecordDecl>(D); int count = 0; - if (!isa<CXXRecordDecl>(record)) { - S.Diag(Attr.getLoc(), diag::err_attribute_vecreturn_only_vector_member); + if (!isa<CXXRecordDecl>(R)) { + S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_vector_member); return; } - if (!cast<CXXRecordDecl>(record)->isPOD()) { - S.Diag(Attr.getLoc(), diag::err_attribute_vecreturn_only_pod_record); + if (!cast<CXXRecordDecl>(R)->isPOD()) { + S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_pod_record); return; } - for (const auto *I : record->fields()) { + for (const auto *I : R->fields()) { if ((count == 1) || !I->getType()->isVectorType()) { - S.Diag(Attr.getLoc(), diag::err_attribute_vecreturn_only_vector_member); + S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_vector_member); return; } count++; } - D->addAttr(::new (S.Context) - VecReturnAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) VecReturnAttr( + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { if (isa<ParmVarDecl>(D)) { // [[carries_dependency]] can only be applied to a parameter if it is a // parameter of a function declaration or lambda. if (!(Scope->getFlags() & clang::Scope::FunctionDeclarationScope)) { - S.Diag(Attr.getLoc(), + S.Diag(AL.getLoc(), diag::err_carries_dependency_param_not_function_decl); return; } } D->addAttr(::new (S.Context) CarriesDependencyAttr( - Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleNotTailCalledAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<AlwaysInlineAttr>(S, D, Attr.getRange(), - Attr.getName())) - return; - - D->addAttr(::new (S.Context) NotTailCalledAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); -} - -static void handleDisableTailCallsAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<NakedAttr>(S, D, Attr.getRange(), - Attr.getName())) - return; - - D->addAttr(::new (S.Context) DisableTailCallsAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); -} - -static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { - if (VD->hasLocalStorage()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); - return; - } - } else if (!isFunctionOrMethod(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedVariableOrFunction; - return; - } - - D->addAttr(::new (S.Context) - UsedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - bool IsCXX17Attr = Attr.isCXX11Attribute() && !Attr.getScopeName(); - - if (IsCXX17Attr && isa<VarDecl>(D)) { - // The C++17 spelling of this attribute cannot be applied to a static data - // member per [dcl.attr.unused]p2. - if (cast<VarDecl>(D)->isStaticDataMember()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedForMaybeUnused; - return; - } - } +static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + bool IsCXX17Attr = AL.isCXX11Attribute() && !AL.getScopeName(); // If this is spelled as the standard C++17 attribute, but not in C++17, warn // about using it as an extension. if (!S.getLangOpts().CPlusPlus17 && IsCXX17Attr) - S.Diag(Attr.getLoc(), diag::ext_cxx17_attr) << Attr.getName(); + S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL.getName(); D->addAttr(::new (S.Context) UnusedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } -static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t priority = ConstructorAttr::DefaultPriority; - if (Attr.getNumArgs() && - !checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), priority)) + if (AL.getNumArgs() && + !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority)) return; D->addAttr(::new (S.Context) - ConstructorAttr(Attr.getRange(), S.Context, priority, - Attr.getAttributeSpellingListIndex())); + ConstructorAttr(AL.getRange(), S.Context, priority, + AL.getAttributeSpellingListIndex())); } -static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t priority = DestructorAttr::DefaultPriority; - if (Attr.getNumArgs() && - !checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), priority)) + if (AL.getNumArgs() && + !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority)) return; D->addAttr(::new (S.Context) - DestructorAttr(Attr.getRange(), S.Context, priority, - Attr.getAttributeSpellingListIndex())); + DestructorAttr(AL.getRange(), S.Context, priority, + AL.getAttributeSpellingListIndex())); } template <typename AttrTy> -static void handleAttrWithMessage(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleAttrWithMessage(Sema &S, Decl *D, const ParsedAttr &AL) { // Handle the case where the attribute has a text message. StringRef Str; - if (Attr.getNumArgs() == 1 && !S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (AL.getNumArgs() == 1 && !S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; - D->addAttr(::new (S.Context) AttrTy(Attr.getRange(), S.Context, Str, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AttrTy(AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); } static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { if (!cast<ObjCProtocolDecl>(D)->isThisDeclarationADefinition()) { - S.Diag(Attr.getLoc(), diag::err_objc_attr_protocol_requires_definition) - << Attr.getName() << Attr.getRange(); + S.Diag(AL.getLoc(), diag::err_objc_attr_protocol_requires_definition) + << AL.getName() << AL.getRange(); return; } D->addAttr(::new (S.Context) - ObjCExplicitProtocolImplAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ObjCExplicitProtocolImplAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } static bool checkAvailabilityAttr(Sema &S, SourceRange Range, @@ -2252,7 +2156,7 @@ static bool checkAvailabilityAttr(Sema &S, SourceRange Range, return false; } -/// \brief Check whether the two versions match. +/// Check whether the two versions match. /// /// If either version tuple is empty, then they are assumed to match. If /// \p BeforeIsOkay is true, then \p X can be less than or equal to \p Y. @@ -2302,7 +2206,7 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, if (D->hasAttrs()) { AttrVec &Attrs = D->getAttrs(); for (unsigned i = 0, e = Attrs.size(); i != e;) { - const AvailabilityAttr *OldAA = dyn_cast<AvailabilityAttr>(Attrs[i]); + const auto *OldAA = dyn_cast<AvailabilityAttr>(Attrs[i]); if (!OldAA) { ++i; continue; @@ -2434,37 +2338,34 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, return nullptr; } -static void handleAvailabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 1)) +static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeNumArgs(S, AL, 1)) return; - IdentifierLoc *Platform = Attr.getArgAsIdent(0); - unsigned Index = Attr.getAttributeSpellingListIndex(); - + IdentifierLoc *Platform = AL.getArgAsIdent(0); + unsigned Index = AL.getAttributeSpellingListIndex(); + IdentifierInfo *II = Platform->Ident; if (AvailabilityAttr::getPrettyPlatformName(II->getName()).empty()) S.Diag(Platform->Loc, diag::warn_availability_unknown_platform) << Platform->Ident; - NamedDecl *ND = dyn_cast<NamedDecl>(D); + auto *ND = dyn_cast<NamedDecl>(D); if (!ND) // We warned about this already, so just return. return; - AvailabilityChange Introduced = Attr.getAvailabilityIntroduced(); - AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated(); - AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted(); - bool IsUnavailable = Attr.getUnavailableLoc().isValid(); - bool IsStrict = Attr.getStrictLoc().isValid(); + AvailabilityChange Introduced = AL.getAvailabilityIntroduced(); + AvailabilityChange Deprecated = AL.getAvailabilityDeprecated(); + AvailabilityChange Obsoleted = AL.getAvailabilityObsoleted(); + bool IsUnavailable = AL.getUnavailableLoc().isValid(); + bool IsStrict = AL.getStrictLoc().isValid(); StringRef Str; - if (const StringLiteral *SE = - dyn_cast_or_null<StringLiteral>(Attr.getMessageExpr())) + if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getMessageExpr())) Str = SE->getString(); StringRef Replacement; - if (const StringLiteral *SE = - dyn_cast_or_null<StringLiteral>(Attr.getReplacementExpr())) + if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getReplacementExpr())) Replacement = SE->getString(); - AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, Attr.getRange(), II, + AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, AL.getRange(), II, false/*Implicit*/, Introduced.Version, Deprecated.Version, @@ -2509,7 +2410,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version); AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, - Attr.getRange(), + AL.getRange(), NewII, true/*Implicit*/, NewIntroduced, @@ -2534,7 +2435,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, if (NewII) { AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, - Attr.getRange(), + AL.getRange(), NewII, true/*Implicit*/, Introduced.Version, @@ -2552,23 +2453,23 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, } static void handleExternalSourceSymbolAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; - assert(checkAttributeAtMostNumArgs(S, Attr, 3) && + assert(checkAttributeAtMostNumArgs(S, AL, 3) && "Invalid number of arguments in an external_source_symbol attribute"); StringRef Language; - if (const auto *SE = dyn_cast_or_null<StringLiteral>(Attr.getArgAsExpr(0))) + if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getArgAsExpr(0))) Language = SE->getString(); StringRef DefinedIn; - if (const auto *SE = dyn_cast_or_null<StringLiteral>(Attr.getArgAsExpr(1))) + if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getArgAsExpr(1))) DefinedIn = SE->getString(); - bool IsGeneratedDeclaration = Attr.getArgAsIdent(2) != nullptr; + bool IsGeneratedDeclaration = AL.getArgAsIdent(2) != nullptr; D->addAttr(::new (S.Context) ExternalSourceSymbolAttr( - Attr.getRange(), S.Context, Language, DefinedIn, IsGeneratedDeclaration, - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, Language, DefinedIn, IsGeneratedDeclaration, + AL.getAttributeSpellingListIndex())); } template <class T> @@ -2601,12 +2502,12 @@ TypeVisibilityAttr *Sema::mergeTypeVisibilityAttr(Decl *D, SourceRange Range, AttrSpellingListIndex); } -static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr, +static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL, bool isTypeVisibility) { // Visibility attributes don't mean anything on a typedef. if (isa<TypedefNameDecl>(D)) { - S.Diag(Attr.getRange().getBegin(), diag::warn_attribute_ignored) - << Attr.getName(); + S.Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored) + << AL.getName(); return; } @@ -2615,84 +2516,82 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr, !(isa<TagDecl>(D) || isa<ObjCInterfaceDecl>(D) || isa<NamespaceDecl>(D))) { - S.Diag(Attr.getRange().getBegin(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedTypeOrNamespace; + S.Diag(AL.getRange().getBegin(), diag::err_attribute_wrong_decl_type) + << AL.getName() << ExpectedTypeOrNamespace; return; } // Check that the argument is a string literal. StringRef TypeStr; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, TypeStr, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, TypeStr, &LiteralLoc)) return; VisibilityAttr::VisibilityType type; if (!VisibilityAttr::ConvertStrToVisibilityType(TypeStr, type)) { S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported) - << Attr.getName() << TypeStr; + << AL.getName() << TypeStr; return; } - + // Complain about attempts to use protected visibility on targets // (like Darwin) that don't support it. if (type == VisibilityAttr::Protected && !S.Context.getTargetInfo().hasProtectedVisibility()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_protected_visibility); + S.Diag(AL.getLoc(), diag::warn_attribute_protected_visibility); type = VisibilityAttr::Default; } - unsigned Index = Attr.getAttributeSpellingListIndex(); - clang::Attr *newAttr; + unsigned Index = AL.getAttributeSpellingListIndex(); + Attr *newAttr; if (isTypeVisibility) { - newAttr = S.mergeTypeVisibilityAttr(D, Attr.getRange(), + newAttr = S.mergeTypeVisibilityAttr(D, AL.getRange(), (TypeVisibilityAttr::VisibilityType) type, Index); } else { - newAttr = S.mergeVisibilityAttr(D, Attr.getRange(), type, Index); + newAttr = S.mergeVisibilityAttr(D, AL.getRange(), type, Index); } if (newAttr) D->addAttr(newAttr); } -static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl, - const AttributeList &Attr) { - ObjCMethodDecl *method = cast<ObjCMethodDecl>(decl); - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIdentifier; +static void handleObjCMethodFamilyAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + const auto *M = cast<ObjCMethodDecl>(D); + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 1 << AANT_ArgumentIdentifier; return; } - IdentifierLoc *IL = Attr.getArgAsIdent(0); + 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) << Attr.getName() - << IL->Ident; + S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) + << AL.getName() << IL->Ident; return; } if (F == ObjCMethodFamilyAttr::OMF_init && - !method->getReturnType()->isObjCObjectPointerType()) { - S.Diag(method->getLocation(), diag::err_init_method_bad_return_type) - << method->getReturnType(); + !M->getReturnType()->isObjCObjectPointerType()) { + S.Diag(M->getLocation(), diag::err_init_method_bad_return_type) + << M->getReturnType(); // Ignore the attribute. return; } - method->addAttr(new (S.Context) ObjCMethodFamilyAttr(Attr.getRange(), - S.Context, F, - Attr.getAttributeSpellingListIndex())); + D->addAttr(new (S.Context) ObjCMethodFamilyAttr( + AL.getRange(), S.Context, F, AL.getAttributeSpellingListIndex())); } -static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) { - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { +static void handleObjCNSObject(Sema &S, Decl *D, const ParsedAttr &AL) { + if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { QualType T = TD->getUnderlyingType(); if (!T->isCARCBridgableType()) { S.Diag(TD->getLocation(), diag::err_nsobject_attribute); return; } } - else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) { + else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) { QualType T = PD->getType(); if (!T->isCARCBridgableType()) { S.Diag(PD->getLocation(), diag::err_nsobject_attribute); @@ -2705,16 +2604,16 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) { // @property (retain, nonatomic) struct Bork *Q __attribute__((NSObject)); // // In this case it follows tradition and suppresses an error in the above - // case. + // case. S.Diag(D->getLocation(), diag::warn_nsobject_attribute); } D->addAttr(::new (S.Context) - ObjCNSObjectAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ObjCNSObjectAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleObjCIndependentClass(Sema &S, Decl *D, const AttributeList &Attr) { - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { +static void handleObjCIndependentClass(Sema &S, Decl *D, const ParsedAttr &AL) { + if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { QualType T = TD->getUnderlyingType(); if (!T->isObjCObjectPointerType()) { S.Diag(TD->getLocation(), diag::warn_ptr_independentclass_attribute); @@ -2725,45 +2624,45 @@ static void handleObjCIndependentClass(Sema &S, Decl *D, const AttributeList &At return; } D->addAttr(::new (S.Context) - ObjCIndependentClassAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ObjCIndependentClassAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIdentifier; +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.getName() << 1 << AANT_ArgumentIdentifier; return; } - IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident; + IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; BlocksAttr::BlockType type; if (!BlocksAttr::ConvertStrToBlockType(II->getName(), type)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << Attr.getName() << II; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << II; return; } D->addAttr(::new (S.Context) - BlocksAttr(Attr.getRange(), S.Context, type, - Attr.getAttributeSpellingListIndex())); + BlocksAttr(AL.getRange(), S.Context, type, + AL.getAttributeSpellingListIndex())); } -static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { unsigned sentinel = (unsigned)SentinelAttr::DefaultSentinel; - if (Attr.getNumArgs() > 0) { - Expr *E = Attr.getArgAsExpr(0); + if (AL.getNumArgs() > 0) { + Expr *E = AL.getArgAsExpr(0); llvm::APSInt Idx(32); if (E->isTypeDependent() || E->isValueDependent() || !E->isIntegerConstantExpr(Idx, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIntegerConstant + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 1 << AANT_ArgumentIntegerConstant << E->getSourceRange(); return; } if (Idx.isSigned() && Idx.isNegative()) { - S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_less_than_zero) + S.Diag(AL.getLoc(), diag::err_attribute_sentinel_less_than_zero) << E->getSourceRange(); return; } @@ -2772,13 +2671,13 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { } unsigned nullPos = (unsigned)SentinelAttr::DefaultNullPos; - if (Attr.getNumArgs() > 1) { - Expr *E = Attr.getArgAsExpr(1); + if (AL.getNumArgs() > 1) { + Expr *E = AL.getArgAsExpr(1); llvm::APSInt Idx(32); if (E->isTypeDependent() || E->isValueDependent() || !E->isIntegerConstantExpr(Idx, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 2 << AANT_ArgumentIntegerConstant + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 2 << AANT_ArgumentIntegerConstant << E->getSourceRange(); return; } @@ -2787,34 +2686,34 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { if ((Idx.isSigned() && Idx.isNegative()) || nullPos > 1) { // FIXME: This error message could be improved, it would be nice // to say what the bounds actually are. - S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_not_zero_or_one) + S.Diag(AL.getLoc(), diag::err_attribute_sentinel_not_zero_or_one) << E->getSourceRange(); return; } } - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { const FunctionType *FT = FD->getType()->castAs<FunctionType>(); if (isa<FunctionNoProtoType>(FT)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_named_arguments); + S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_named_arguments); return; } if (!cast<FunctionProtoType>(FT)->isVariadic()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; + S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; return; } - } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { if (!MD->isVariadic()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; + S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; return; } - } else if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) { + } else if (const auto *BD = dyn_cast<BlockDecl>(D)) { if (!BD->isVariadic()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 1; + S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 1; return; } - } else if (const VarDecl *V = dyn_cast<VarDecl>(D)) { + } else if (const auto *V = dyn_cast<VarDecl>(D)) { QualType Ty = V->getType(); if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) { const FunctionType *FT = Ty->isFunctionPointerType() @@ -2822,84 +2721,83 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>(); if (!cast<FunctionProtoType>(FT)->isVariadic()) { int m = Ty->isFunctionPointerType() ? 0 : 1; - S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m; + S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m; return; } } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionMethodOrBlock; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedFunctionMethodOrBlock; return; } } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionMethodOrBlock; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedFunctionMethodOrBlock; return; } D->addAttr(::new (S.Context) - SentinelAttr(Attr.getRange(), S.Context, sentinel, nullPos, - Attr.getAttributeSpellingListIndex())); + SentinelAttr(AL.getRange(), S.Context, sentinel, nullPos, + AL.getAttributeSpellingListIndex())); } -static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->getFunctionType() && D->getFunctionType()->getReturnType()->isVoidType()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method) - << Attr.getName() << 0; + S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) + << AL.getName() << 0; return; } - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) if (MD->getReturnType()->isVoidType()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method) - << Attr.getName() << 1; + S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) + << AL.getName() << 1; return; } - + // If this is spelled as the standard C++17 attribute, but not in C++17, warn // about using it as an extension. - if (!S.getLangOpts().CPlusPlus17 && Attr.isCXX11Attribute() && - !Attr.getScopeName()) - S.Diag(Attr.getLoc(), diag::ext_cxx17_attr) << Attr.getName(); + if (!S.getLangOpts().CPlusPlus17 && AL.isCXX11Attribute() && + !AL.getScopeName()) + S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL.getName(); - D->addAttr(::new (S.Context) - WarnUnusedResultAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + WarnUnusedResultAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleWeakImportAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // weak_import only applies to variable & function declarations. bool isDef = false; if (!D->canBeWeakImported(isDef)) { if (isDef) - S.Diag(Attr.getLoc(), diag::warn_attribute_invalid_on_definition) + S.Diag(AL.getLoc(), diag::warn_attribute_invalid_on_definition) << "weak_import"; else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D) || (S.Context.getTargetInfo().getTriple().isOSDarwin() && (isa<ObjCInterfaceDecl>(D) || isa<EnumDecl>(D)))) { // Nothing to warn about here. } else - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedVariableOrFunction; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedVariableOrFunction; return; } D->addAttr(::new (S.Context) - WeakImportAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + WeakImportAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } // Handles reqd_work_group_size and work_group_size_hint. template <typename WorkGroupAttr> -static void handleWorkGroupSize(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t WGSize[3]; for (unsigned i = 0; i < 3; ++i) { - const Expr *E = Attr.getArgAsExpr(i); - if (!checkUInt32Argument(S, Attr, E, WGSize[i], i)) + const Expr *E = AL.getArgAsExpr(i); + if (!checkUInt32Argument(S, AL, E, WGSize[i], i)) return; if (WGSize[i] == 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_is_zero) - << Attr.getName() << E->getSourceRange(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) + << AL.getName() << E->getSourceRange(); return; } } @@ -2908,73 +2806,81 @@ static void handleWorkGroupSize(Sema &S, Decl *D, if (Existing && !(Existing->getXDim() == WGSize[0] && Existing->getYDim() == WGSize[1] && Existing->getZDim() == WGSize[2])) - S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL.getName(); - D->addAttr(::new (S.Context) WorkGroupAttr(Attr.getRange(), S.Context, + D->addAttr(::new (S.Context) WorkGroupAttr(AL.getRange(), S.Context, WGSize[0], WGSize[1], WGSize[2], - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } // Handles intel_reqd_sub_group_size. -static void handleSubGroupSize(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleSubGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t SGSize; - const Expr *E = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(S, Attr, E, SGSize)) + const Expr *E = AL.getArgAsExpr(0); + if (!checkUInt32Argument(S, AL, E, SGSize)) return; if (SGSize == 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_is_zero) - << Attr.getName() << E->getSourceRange(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) + << AL.getName() << E->getSourceRange(); return; } OpenCLIntelReqdSubGroupSizeAttr *Existing = D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>(); if (Existing && Existing->getSubGroupSize() != SGSize) - S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL.getName(); D->addAttr(::new (S.Context) OpenCLIntelReqdSubGroupSizeAttr( - Attr.getRange(), S.Context, SGSize, - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, SGSize, + AL.getAttributeSpellingListIndex())); } -static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) { - if (!Attr.hasParsedType()) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 1; +static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!AL.hasParsedType()) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) + << AL.getName() << 1; return; } TypeSourceInfo *ParmTSI = nullptr; - QualType ParmType = S.GetTypeFromParser(Attr.getTypeArg(), &ParmTSI); + QualType ParmType = S.GetTypeFromParser(AL.getTypeArg(), &ParmTSI); assert(ParmTSI && "no type source info for attribute argument"); if (!ParmType->isExtVectorType() && !ParmType->isFloatingType() && (ParmType->isBooleanType() || !ParmType->isIntegralType(S.getASTContext()))) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_vec_type_hint) + S.Diag(AL.getLoc(), diag::err_attribute_argument_vec_type_hint) << ParmType; return; } if (VecTypeHintAttr *A = D->getAttr<VecTypeHintAttr>()) { if (!S.Context.hasSameType(A->getTypeHint(), ParmType)) { - S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL.getName(); return; } } - D->addAttr(::new (S.Context) VecTypeHintAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) VecTypeHintAttr(AL.getLoc(), S.Context, ParmTSI, - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name, unsigned AttrSpellingListIndex) { + // Explicit or partial specializations do not inherit + // the section attribute from the primary template. + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + if (AttrSpellingListIndex == SectionAttr::Declspec_allocate && + FD->isFunctionTemplateSpecialization()) + return nullptr; + } if (SectionAttr *ExistingAttr = D->getAttr<SectionAttr>()) { if (ExistingAttr->getName() == Name) return nullptr; - Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section); + Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section) + << 1 /*section*/; Diag(Range.getBegin(), diag::note_previous_attribute); return nullptr; } @@ -2985,18 +2891,19 @@ SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range, bool Sema::checkSectionName(SourceLocation LiteralLoc, StringRef SecName) { std::string Error = Context.getTargetInfo().isValidSectionSpecifier(SecName); if (!Error.empty()) { - Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error; + Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error + << 1 /*'section'*/; return false; } return true; } -static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Make sure that there is a string literal as the sections's single // argument. StringRef Str; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc)) return; if (!S.checkSectionName(LiteralLoc, Str)) @@ -3010,12 +2917,65 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - unsigned Index = Attr.getAttributeSpellingListIndex(); - SectionAttr *NewAttr = S.mergeSectionAttr(D, Attr.getRange(), Str, Index); + unsigned Index = AL.getAttributeSpellingListIndex(); + SectionAttr *NewAttr = S.mergeSectionAttr(D, AL.getRange(), Str, Index); if (NewAttr) D->addAttr(NewAttr); } +static bool checkCodeSegName(Sema&S, SourceLocation LiteralLoc, StringRef CodeSegName) { + std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(CodeSegName); + if (!Error.empty()) { + S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error + << 0 /*'code-seg'*/; + return false; + } + return true; +} + +CodeSegAttr *Sema::mergeCodeSegAttr(Decl *D, SourceRange Range, + StringRef Name, + unsigned AttrSpellingListIndex) { + // Explicit or partial specializations do not inherit + // the code_seg attribute from the primary template. + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isFunctionTemplateSpecialization()) + return nullptr; + } + if (const auto *ExistingAttr = D->getAttr<CodeSegAttr>()) { + if (ExistingAttr->getName() == Name) + return nullptr; + Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section) + << 0 /*codeseg*/; + Diag(Range.getBegin(), diag::note_previous_attribute); + return nullptr; + } + return ::new (Context) CodeSegAttr(Range, Context, Name, + AttrSpellingListIndex); +} + +static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + StringRef Str; + SourceLocation LiteralLoc; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc)) + return; + if (!checkCodeSegName(S, LiteralLoc, Str)) + return; + if (const auto *ExistingAttr = D->getAttr<CodeSegAttr>()) { + if (!ExistingAttr->isImplicit()) { + S.Diag(AL.getLoc(), + ExistingAttr->getName() == Str + ? diag::warn_duplicate_codeseg_attribute + : diag::err_conflicting_codeseg_attribute); + return; + } + D->dropAttr<CodeSegAttr>(); + } + if (CodeSegAttr *CSA = S.mergeCodeSegAttr(D, AL.getRange(), Str, + AL.getAttributeSpellingListIndex())) + D->addAttr(CSA); +} + // Check for things we'd like to warn about. Multiversioning issues are // handled later in the process, once we know how many exist. bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { @@ -3044,30 +3004,50 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { << Unsupported << None << CurFeature; } - return true; + return false; } -static void handleTargetAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Str; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc) || - !S.checkTargetAttr(LiteralLoc, Str)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) || + S.checkTargetAttr(LiteralLoc, Str)) return; - unsigned Index = Attr.getAttributeSpellingListIndex(); + + unsigned Index = AL.getAttributeSpellingListIndex(); TargetAttr *NewAttr = - ::new (S.Context) TargetAttr(Attr.getRange(), S.Context, Str, Index); + ::new (S.Context) TargetAttr(AL.getRange(), S.Context, Str, Index); D->addAttr(NewAttr); } -static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { - Expr *E = Attr.getArgAsExpr(0); +static void handleMinVectorWidthAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + Expr *E = AL.getArgAsExpr(0); + uint32_t VecWidth; + if (!checkUInt32Argument(S, AL, E, VecWidth)) { + AL.setInvalid(); + return; + } + + MinVectorWidthAttr *Existing = D->getAttr<MinVectorWidthAttr>(); + if (Existing && Existing->getVectorWidth() != VecWidth) { + S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL.getName(); + return; + } + + D->addAttr(::new (S.Context) + MinVectorWidthAttr(AL.getRange(), S.Context, VecWidth, + AL.getAttributeSpellingListIndex())); +} + +static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + Expr *E = AL.getArgAsExpr(0); SourceLocation Loc = E->getExprLoc(); FunctionDecl *FD = nullptr; DeclarationNameInfo NI; // gcc only allows for simple identifiers. Since we support more than gcc, we // will warn the user. - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + if (auto *DRE = dyn_cast<DeclRefExpr>(E)) { if (DRE->hasQualifier()) S.Diag(Loc, diag::warn_cleanup_ext); FD = dyn_cast<FunctionDecl>(DRE->getDecl()); @@ -3077,7 +3057,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { << NI.getName(); return; } - } else if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { + } else if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { if (ULE->hasExplicitTemplateArgs()) S.Diag(Loc, diag::warn_cleanup_ext); FD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true); @@ -3112,49 +3092,49 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { } D->addAttr(::new (S.Context) - CleanupAttr(Attr.getRange(), S.Context, FD, - Attr.getAttributeSpellingListIndex())); + CleanupAttr(AL.getRange(), S.Context, FD, + AL.getAttributeSpellingListIndex())); } static void handleEnumExtensibilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 0 << AANT_ArgumentIdentifier; + const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 0 << AANT_ArgumentIdentifier; return; } EnumExtensibilityAttr::Kind ExtensibilityKind; - IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident; + IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; if (!EnumExtensibilityAttr::ConvertStrToKind(II->getName(), ExtensibilityKind)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << Attr.getName() << II; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << II; return; } D->addAttr(::new (S.Context) EnumExtensibilityAttr( - Attr.getRange(), S.Context, ExtensibilityKind, - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, ExtensibilityKind, + AL.getAttributeSpellingListIndex())); } /// Handle __attribute__((format_arg((idx)))) attribute based on /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html -static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) { - Expr *IdxExpr = Attr.getArgAsExpr(0); - uint64_t Idx; - if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 1, IdxExpr, Idx)) +static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + Expr *IdxExpr = AL.getArgAsExpr(0); + ParamIdx Idx; + if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, IdxExpr, Idx)) return; // Make sure the format string is really a string. - QualType Ty = getFunctionOrMethodParamType(D, Idx); + QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex()); bool NotNSStringTy = !isNSStringType(Ty, S.Context); if (NotNSStringTy && !isCFStringType(Ty, S.Context) && (!Ty->isPointerType() || !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) { - S.Diag(Attr.getLoc(), diag::err_format_attribute_not) + S.Diag(AL.getLoc(), diag::err_format_attribute_not) << "a string type" << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0); return; @@ -3164,21 +3144,14 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) { !isCFStringType(Ty, S.Context) && (!Ty->isPointerType() || !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) { - S.Diag(Attr.getLoc(), diag::err_format_attribute_result_not) + S.Diag(AL.getLoc(), diag::err_format_attribute_result_not) << (NotNSStringTy ? "string type" : "NSString") << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0); return; } - // We cannot use the Idx returned from checkFunctionOrMethodParameterIndex - // because that has corrected for the implicit this parameter, and is zero- - // based. The attribute expects what the user wrote explicitly. - llvm::APSInt Val; - IdxExpr->EvaluateAsInt(Val, S.Context); - - D->addAttr(::new (S.Context) - FormatArgAttr(Attr.getRange(), S.Context, Val.getZExtValue(), - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) FormatArgAttr( + AL.getRange(), S.Context, Idx, AL.getAttributeSpellingListIndex())); } enum FormatAttrKind { @@ -3214,43 +3187,42 @@ static FormatAttrKind getFormatAttrKind(StringRef Format) { /// Handle __attribute__((init_priority(priority))) attributes based on /// http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html -static void handleInitPriorityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.getLangOpts().CPlusPlus) { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL.getName(); return; } - + if (S.getCurFunctionOrMethodDecl()) { - S.Diag(Attr.getLoc(), diag::err_init_priority_object_attr); - Attr.setInvalid(); + S.Diag(AL.getLoc(), diag::err_init_priority_object_attr); + AL.setInvalid(); return; } QualType T = cast<VarDecl>(D)->getType(); if (S.Context.getAsArrayType(T)) T = S.Context.getBaseElementType(T); if (!T->getAs<RecordType>()) { - S.Diag(Attr.getLoc(), diag::err_init_priority_object_attr); - Attr.setInvalid(); + S.Diag(AL.getLoc(), diag::err_init_priority_object_attr); + AL.setInvalid(); return; } - Expr *E = Attr.getArgAsExpr(0); + Expr *E = AL.getArgAsExpr(0); uint32_t prioritynum; - if (!checkUInt32Argument(S, Attr, E, prioritynum)) { - Attr.setInvalid(); + if (!checkUInt32Argument(S, AL, E, prioritynum)) { + AL.setInvalid(); return; } if (prioritynum < 101 || prioritynum > 65535) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_outof_range) - << E->getSourceRange() << Attr.getName() << 101 << 65535; - Attr.setInvalid(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_outof_range) + << E->getSourceRange() << AL.getName() << 101 << 65535; + AL.setInvalid(); return; } D->addAttr(::new (S.Context) - InitPriorityAttr(Attr.getRange(), S.Context, prioritynum, - Attr.getAttributeSpellingListIndex())); + InitPriorityAttr(AL.getRange(), S.Context, prioritynum, + AL.getAttributeSpellingListIndex())); } FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, @@ -3276,10 +3248,10 @@ FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, /// Handle __attribute__((format(type,idx,firstarg))) attributes based on /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html -static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIdentifier; +static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 1 << AANT_ArgumentIdentifier; return; } @@ -3288,7 +3260,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { bool HasImplicitThisParam = isInstanceMethod(D); unsigned NumArgs = getFunctionOrMethodNumParams(D) + HasImplicitThisParam; - IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident; + IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; StringRef Format = II->getName(); if (normalizeName(Format)) { @@ -3298,25 +3270,25 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Check for supported formats. FormatAttrKind Kind = getFormatAttrKind(Format); - + if (Kind == IgnoredFormat) return; - + if (Kind == InvalidFormat) { - S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << Attr.getName() << II->getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << II->getName(); return; } // checks for the 2nd argument - Expr *IdxExpr = Attr.getArgAsExpr(1); + Expr *IdxExpr = AL.getArgAsExpr(1); uint32_t Idx; - if (!checkUInt32Argument(S, Attr, IdxExpr, Idx, 2)) + if (!checkUInt32Argument(S, AL, IdxExpr, Idx, 2)) return; if (Idx < 1 || Idx > NumArgs) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) - << Attr.getName() << 2 << IdxExpr->getSourceRange(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL.getName() << 2 << IdxExpr->getSourceRange(); return; } @@ -3325,7 +3297,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (HasImplicitThisParam) { if (ArgIdx == 0) { - S.Diag(Attr.getLoc(), + S.Diag(AL.getLoc(), diag::err_format_attribute_implicit_this_format_string) << IdxExpr->getSourceRange(); return; @@ -3338,7 +3310,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (Kind == CFStringFormat) { if (!isCFStringType(Ty, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_format_attribute_not) + S.Diag(AL.getLoc(), diag::err_format_attribute_not) << "a CFString" << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, ArgIdx); return; @@ -3347,23 +3319,23 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { // FIXME: do we need to check if the type is NSString*? What are the // semantics? if (!isNSStringType(Ty, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_format_attribute_not) + S.Diag(AL.getLoc(), diag::err_format_attribute_not) << "an NSString" << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, ArgIdx); return; } } else if (!Ty->isPointerType() || !Ty->getAs<PointerType>()->getPointeeType()->isCharType()) { - S.Diag(Attr.getLoc(), diag::err_format_attribute_not) + S.Diag(AL.getLoc(), diag::err_format_attribute_not) << "a string type" << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, ArgIdx); return; } // check the 3rd argument - Expr *FirstArgExpr = Attr.getArgAsExpr(2); + Expr *FirstArgExpr = AL.getArgAsExpr(2); uint32_t FirstArg; - if (!checkUInt32Argument(S, Attr, FirstArgExpr, FirstArg, 3)) + if (!checkUInt32Argument(S, AL, FirstArgExpr, FirstArg, 3)) return; // check if the function is variadic if the 3rd argument non-zero @@ -3380,43 +3352,42 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { // variable the input is just the current time + the format string. if (Kind == StrftimeFormat) { if (FirstArg != 0) { - S.Diag(Attr.getLoc(), diag::err_format_strftime_third_parameter) + S.Diag(AL.getLoc(), diag::err_format_strftime_third_parameter) << FirstArgExpr->getSourceRange(); return; } // if 0 it disables parameter checking (to use with e.g. va_list) } else if (FirstArg != 0 && FirstArg != NumArgs) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) - << Attr.getName() << 3 << FirstArgExpr->getSourceRange(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL.getName() << 3 << FirstArgExpr->getSourceRange(); return; } - FormatAttr *NewAttr = S.mergeFormatAttr(D, Attr.getRange(), II, + FormatAttr *NewAttr = S.mergeFormatAttr(D, AL.getRange(), II, Idx, FirstArg, - Attr.getAttributeSpellingListIndex()); + AL.getAttributeSpellingListIndex()); if (NewAttr) D->addAttr(NewAttr); } -static void handleTransparentUnionAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Try to find the underlying union declaration. RecordDecl *RD = nullptr; - TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D); + const auto *TD = dyn_cast<TypedefNameDecl>(D); if (TD && TD->getUnderlyingType()->isUnionType()) RD = TD->getUnderlyingType()->getAsUnionType()->getDecl(); else RD = dyn_cast<RecordDecl>(D); if (!RD || !RD->isUnion()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedUnion; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedUnion; return; } if (!RD->isCompleteDefinition()) { if (!RD->isBeingDefined()) - S.Diag(Attr.getLoc(), + S.Diag(AL.getLoc(), diag::warn_transparent_union_attribute_not_definition); return; } @@ -3424,7 +3395,7 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, RecordDecl::field_iterator Field = RD->field_begin(), FieldEnd = RD->field_end(); if (Field == FieldEnd) { - S.Diag(Attr.getLoc(), diag::warn_transparent_union_attribute_zero_fields); + S.Diag(AL.getLoc(), diag::warn_transparent_union_attribute_zero_fields); return; } @@ -3468,15 +3439,15 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, } RD->addAttr(::new (S.Context) - TransparentUnionAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + TransparentUnionAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAnnotateAttr(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(Attr, 0, Str)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; // Don't duplicate annotations that are already set. @@ -3484,16 +3455,15 @@ static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (I->getAnnotation() == Str) return; } - + D->addAttr(::new (S.Context) - AnnotateAttr(Attr.getRange(), S.Context, Str, - Attr.getAttributeSpellingListIndex())); + AnnotateAttr(AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); } -static void handleAlignValueAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - S.AddAlignValueAttr(Attr.getRange(), D, Attr.getArgAsExpr(0), - Attr.getAttributeSpellingListIndex()); +static void handleAlignValueAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + S.AddAlignValueAttr(AL.getRange(), D, AL.getArgAsExpr(0), + AL.getAttributeSpellingListIndex()); } void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, @@ -3502,9 +3472,9 @@ void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, SourceLocation AttrLoc = AttrRange.getBegin(); QualType T; - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) + if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) T = TD->getUnderlyingType(); - else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) + else if (const auto *VD = dyn_cast<ValueDecl>(D)) T = VD->getType(); else llvm_unreachable("Unknown decl type for align_value"); @@ -3541,42 +3511,32 @@ void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, D->addAttr(::new (Context) AlignValueAttr(TmpAttr)); } -static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // check the attribute arguments. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 1; + if (AL.getNumArgs() > 1) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) + << AL.getName() << 1; return; } - if (Attr.getNumArgs() == 0) { - D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context, - true, nullptr, Attr.getAttributeSpellingListIndex())); + if (AL.getNumArgs() == 0) { + D->addAttr(::new (S.Context) AlignedAttr(AL.getRange(), S.Context, + true, nullptr, AL.getAttributeSpellingListIndex())); return; } - Expr *E = Attr.getArgAsExpr(0); - if (Attr.isPackExpansion() && !E->containsUnexpandedParameterPack()) { - S.Diag(Attr.getEllipsisLoc(), + Expr *E = AL.getArgAsExpr(0); + if (AL.isPackExpansion() && !E->containsUnexpandedParameterPack()) { + S.Diag(AL.getEllipsisLoc(), diag::err_pack_expansion_without_parameter_packs); return; } - if (!Attr.isPackExpansion() && S.DiagnoseUnexpandedParameterPack(E)) + if (!AL.isPackExpansion() && S.DiagnoseUnexpandedParameterPack(E)) return; - if (E->isValueDependent()) { - if (const auto *TND = dyn_cast<TypedefNameDecl>(D)) { - if (!TND->getUnderlyingType()->isDependentType()) { - S.Diag(Attr.getLoc(), diag::err_alignment_dependent_typedef_name) - << E->getSourceRange(); - return; - } - } - } - - S.AddAlignedAttr(Attr.getRange(), D, E, Attr.getAttributeSpellingListIndex(), - Attr.isPackExpansion()); + S.AddAlignedAttr(AL.getRange(), D, E, AL.getAttributeSpellingListIndex(), + AL.isPackExpansion()); } void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, @@ -3600,12 +3560,12 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, int DiagKind = -1; if (isa<ParmVarDecl>(D)) { DiagKind = 0; - } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) { + } else if (const auto *VD = dyn_cast<VarDecl>(D)) { if (VD->getStorageClass() == SC_Register) DiagKind = 1; if (VD->isExceptionVariable()) DiagKind = 2; - } else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { + } else if (const auto *FD = dyn_cast<FieldDecl>(D)) { if (FD->isBitField()) DiagKind = 3; } else if (!isa<TagDecl>(D)) { @@ -3621,7 +3581,18 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, } } - if (E->isTypeDependent() || E->isValueDependent()) { + if (E->isValueDependent()) { + // We can't support a dependent alignment on a non-dependent type, + // because we have no way to model that a type is "alignment-dependent" + // but not dependent in any other way. + if (const auto *TND = dyn_cast<TypedefNameDecl>(D)) { + if (!TND->getUnderlyingType()->isDependentType()) { + Diag(AttrLoc, diag::err_alignment_dependent_typedef_name) + << E->getSourceRange(); + return; + } + } + // Save dependent expressions in the AST to be instantiated. AlignedAttr *AA = ::new (Context) AlignedAttr(TmpAttr); AA->setPackExpansion(IsPackExpansion); @@ -3629,7 +3600,7 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, return; } - // FIXME: Cache the number on the Attr object? + // FIXME: Cache the number on the AL object? llvm::APSInt Alignment; ExprResult ICE = VerifyIntegerConstantExpression(E, &Alignment, @@ -3667,7 +3638,7 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, unsigned MaxTLSAlign = Context.toCharUnitsFromBits(Context.getTargetInfo().getMaxTLSAlign()) .getQuantity(); - auto *VD = dyn_cast<VarDecl>(D); + const auto *VD = dyn_cast<VarDecl>(D); if (MaxTLSAlign && AlignVal > MaxTLSAlign && VD && VD->getTLSKind() != VarDecl::TLS_None) { Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum) @@ -3684,7 +3655,7 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS, unsigned SpellingListIndex, bool IsPackExpansion) { - // FIXME: Cache the number on the Attr object if non-dependent? + // FIXME: Cache the number on the AL object if non-dependent? // FIXME: Perform checking of type validity AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, false, TS, SpellingListIndex); @@ -3696,11 +3667,11 @@ void Sema::CheckAlignasUnderalignment(Decl *D) { assert(D->hasAttrs() && "no attributes on decl"); QualType UnderlyingTy, DiagTy; - if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + if (const auto *VD = dyn_cast<ValueDecl>(D)) { UnderlyingTy = DiagTy = VD->getType(); } else { UnderlyingTy = DiagTy = Context.getTagDeclType(cast<TagDecl>(D)); - if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) + if (const auto *ED = dyn_cast<EnumDecl>(D)) UnderlyingTy = ED->getIntegerType(); } if (DiagTy->isDependentType() || DiagTy->isIncompleteType()) @@ -3820,18 +3791,18 @@ static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth, /// Despite what would be logical, the mode attribute is a decl attribute, not a /// type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make 'G' be /// HImode, not an intermediate pointer. -static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleModeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // This attribute isn't documented, but glibc uses it. It changes // the width of an int or unsigned int to the specified size. - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName() + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << AL.getName() << AANT_ArgumentIdentifier; return; } - IdentifierInfo *Name = Attr.getArgAsIdent(0)->Ident; + IdentifierInfo *Name = AL.getArgAsIdent(0)->Ident; - S.AddModeAttr(Attr.getRange(), D, Name, Attr.getAttributeSpellingListIndex()); + S.AddModeAttr(AL.getRange(), D, Name, AL.getAttributeSpellingListIndex()); } void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, @@ -3877,9 +3848,9 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, } QualType OldTy; - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) + if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) OldTy = TD->getUnderlyingType(); - else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) { + else if (const auto *ED = dyn_cast<EnumDecl>(D)) { // Something like 'typedef enum { X } __attribute__((mode(XX))) T;'. // Try to get type from enum declaration, default to int. OldTy = ED->getIntegerType(); @@ -3897,7 +3868,7 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, // Base type can also be a vector type (see PR17453). // Distinguish between base type and base element type. QualType OldElemTy = OldTy; - if (const VectorType *VT = OldTy->getAs<VectorType>()) + if (const auto *VT = OldTy->getAs<VectorType>()) OldElemTy = VT->getElementType(); // GCC allows 'mode' attribute on enumeration types (even incomplete), except @@ -3946,7 +3917,7 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, if (VectorSize.getBoolValue()) { NewTy = Context.getVectorType(NewTy, VectorSize.getZExtValue(), VectorType::GenericVector); - } else if (const VectorType *OldVT = OldTy->getAs<VectorType>()) { + } else if (const auto *OldVT = OldTy->getAs<VectorType>()) { // Complex machine mode does not support base vector types. if (ComplexMode) { Diag(AttrLoc, diag::err_complex_mode_vector_type); @@ -3965,9 +3936,9 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, } // Install the new type. - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) + if (auto *TD = dyn_cast<TypedefNameDecl>(D)) TD->setModedTypeSourceInfo(TD->getTypeSourceInfo(), NewTy); - else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) + else if (auto *ED = dyn_cast<EnumDecl>(D)) ED->setIntegerType(NewTy); else cast<ValueDecl>(D)->setType(NewTy); @@ -3976,10 +3947,10 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, ModeAttr(AttrRange, Context, Name, SpellingListIndex)); } -static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleNoDebugAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(::new (S.Context) - NoDebugAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + NoDebugAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, SourceRange Range, @@ -4011,7 +3982,7 @@ InternalLinkageAttr * Sema::mergeInternalLinkageAttr(Decl *D, SourceRange Range, IdentifierInfo *Ident, unsigned AttrSpellingListIndex) { - if (auto VD = dyn_cast<VarDecl>(D)) { + if (const auto *VD = dyn_cast<VarDecl>(D)) { // Attribute applies to Var but not any subclass of it (like ParmVar, // ImplicitParm or VarTemplateSpecialization). if (VD->getKind() != Decl::Var) { @@ -4068,71 +4039,70 @@ OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range, AttrSpellingListIndex); } -static void handleAlwaysInlineAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, Attr.getRange(), - Attr.getName())) +static void handleAlwaysInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, AL.getRange(), + AL.getName())) return; if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr( - D, Attr.getRange(), Attr.getName(), - Attr.getAttributeSpellingListIndex())) + D, AL.getRange(), AL.getName(), + AL.getAttributeSpellingListIndex())) D->addAttr(Inline); } -static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleMinSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (MinSizeAttr *MinSize = S.mergeMinSizeAttr( - D, Attr.getRange(), Attr.getAttributeSpellingListIndex())) + D, AL.getRange(), AL.getAttributeSpellingListIndex())) D->addAttr(MinSize); } -static void handleOptimizeNoneAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleOptimizeNoneAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (OptimizeNoneAttr *Optnone = S.mergeOptimizeNoneAttr( - D, Attr.getRange(), Attr.getAttributeSpellingListIndex())) + D, AL.getRange(), AL.getAttributeSpellingListIndex())) D->addAttr(Optnone); } -static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<CUDASharedAttr>(S, D, Attr.getRange(), - Attr.getName())) +static void handleConstantAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<CUDASharedAttr>(S, D, AL.getRange(), + AL.getName())) return; - auto *VD = cast<VarDecl>(D); + const auto *VD = cast<VarDecl>(D); if (!VD->hasGlobalStorage()) { - S.Diag(Attr.getLoc(), diag::err_cuda_nonglobal_constant); + S.Diag(AL.getLoc(), diag::err_cuda_nonglobal_constant); return; } D->addAttr(::new (S.Context) CUDAConstantAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } -static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<CUDAConstantAttr>(S, D, Attr.getRange(), - Attr.getName())) +static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<CUDAConstantAttr>(S, D, AL.getRange(), + AL.getName())) return; - auto *VD = cast<VarDecl>(D); + const auto *VD = cast<VarDecl>(D); // extern __shared__ is only allowed on arrays with no length (e.g. // "int x[]"). - if (VD->hasExternalStorage() && !isa<IncompleteArrayType>(VD->getType())) { - S.Diag(Attr.getLoc(), diag::err_cuda_extern_shared) << VD; + if (!S.getLangOpts().CUDARelocatableDeviceCode && VD->hasExternalStorage() && + !isa<IncompleteArrayType>(VD->getType())) { + S.Diag(AL.getLoc(), diag::err_cuda_extern_shared) << VD; return; } if (S.getLangOpts().CUDA && VD->hasLocalStorage() && - S.CUDADiagIfHostCode(Attr.getLoc(), diag::err_cuda_host_shared) + S.CUDADiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared) << S.CurrentCUDATarget()) return; D->addAttr(::new (S.Context) CUDASharedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } -static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<CUDADeviceAttr>(S, D, Attr.getRange(), - Attr.getName()) || - checkAttrMutualExclusion<CUDAHostAttr>(S, D, Attr.getRange(), - Attr.getName())) { +static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<CUDADeviceAttr>(S, D, AL.getRange(), + AL.getName()) || + checkAttrMutualExclusion<CUDAHostAttr>(S, D, AL.getRange(), + AL.getName())) { return; } - FunctionDecl *FD = cast<FunctionDecl>(D); + const auto *FD = cast<FunctionDecl>(D); if (!FD->getReturnType()->isVoidType()) { SourceRange RTRange = FD->getReturnTypeSourceRange(); S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return) @@ -4154,88 +4124,88 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { S.Diag(FD->getLocStart(), diag::warn_kern_is_inline) << FD; D->addAttr(::new (S.Context) - CUDAGlobalAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + CUDAGlobalAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { - FunctionDecl *Fn = cast<FunctionDecl>(D); +static void handleGNUInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + const auto *Fn = cast<FunctionDecl>(D); if (!Fn->isInlineSpecified()) { - S.Diag(Attr.getLoc(), diag::warn_gnu_inline_attribute_requires_inline); + S.Diag(AL.getLoc(), diag::warn_gnu_inline_attribute_requires_inline); return; } D->addAttr(::new (S.Context) - GNUInlineAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + GNUInlineAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (hasDeclarator(D)) return; - // Diagnostic is emitted elsewhere: here we store the (valid) Attr + // Diagnostic is emitted elsewhere: here we store the (valid) AL // in the Decl node for syntactic reasoning, e.g., pretty-printing. CallingConv CC; - if (S.CheckCallingConvAttr(Attr, CC, /*FD*/nullptr)) + if (S.CheckCallingConvAttr(AL, CC, /*FD*/nullptr)) return; if (!isa<ObjCMethodDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionOrMethod; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedFunctionOrMethod; return; } - switch (Attr.getKind()) { - case AttributeList::AT_FastCall: + switch (AL.getKind()) { + case ParsedAttr::AT_FastCall: D->addAttr(::new (S.Context) - FastCallAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + FastCallAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_StdCall: + case ParsedAttr::AT_StdCall: D->addAttr(::new (S.Context) - StdCallAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + StdCallAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_ThisCall: + case ParsedAttr::AT_ThisCall: D->addAttr(::new (S.Context) - ThisCallAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ThisCallAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_CDecl: + case ParsedAttr::AT_CDecl: D->addAttr(::new (S.Context) - CDeclAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + CDeclAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_Pascal: + case ParsedAttr::AT_Pascal: D->addAttr(::new (S.Context) - PascalAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + PascalAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_SwiftCall: + case ParsedAttr::AT_SwiftCall: D->addAttr(::new (S.Context) - SwiftCallAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + SwiftCallAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_VectorCall: + case ParsedAttr::AT_VectorCall: D->addAttr(::new (S.Context) - VectorCallAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + VectorCallAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_MSABI: + case ParsedAttr::AT_MSABI: D->addAttr(::new (S.Context) - MSABIAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + MSABIAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_SysVABI: + case ParsedAttr::AT_SysVABI: D->addAttr(::new (S.Context) - SysVABIAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + SysVABIAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_RegCall: + case ParsedAttr::AT_RegCall: D->addAttr(::new (S.Context) RegCallAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_Pcs: { + case ParsedAttr::AT_Pcs: { PcsAttr::PCSType PCS; switch (CC) { case CC_AAPCS: @@ -4249,37 +4219,37 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { } D->addAttr(::new (S.Context) - PcsAttr(Attr.getRange(), S.Context, PCS, - Attr.getAttributeSpellingListIndex())); + PcsAttr(AL.getRange(), S.Context, PCS, + AL.getAttributeSpellingListIndex())); return; } - case AttributeList::AT_IntelOclBicc: + case ParsedAttr::AT_IntelOclBicc: D->addAttr(::new (S.Context) - IntelOclBiccAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + IntelOclBiccAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_PreserveMost: + case ParsedAttr::AT_PreserveMost: D->addAttr(::new (S.Context) PreserveMostAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_PreserveAll: + case ParsedAttr::AT_PreserveAll: D->addAttr(::new (S.Context) PreserveAllAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; default: llvm_unreachable("unexpected attribute kind"); } } -static void handleSuppressAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) +static void handleSuppressAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; std::vector<StringRef> DiagnosticIdentifiers; - for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) { + for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { StringRef RuleName; - if (!S.checkStringLiteralArgumentAttr(Attr, I, RuleName, nullptr)) + if (!S.checkStringLiteralArgumentAttr(AL, I, RuleName, nullptr)) return; // FIXME: Warn if the rule name is unknown. This is tricky because only @@ -4287,11 +4257,11 @@ static void handleSuppressAttr(Sema &S, Decl *D, const AttributeList &Attr) { DiagnosticIdentifiers.push_back(RuleName); } D->addAttr(::new (S.Context) SuppressAttr( - Attr.getRange(), S.Context, DiagnosticIdentifiers.data(), - DiagnosticIdentifiers.size(), Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, DiagnosticIdentifiers.data(), + DiagnosticIdentifiers.size(), AL.getAttributeSpellingListIndex())); } -bool Sema::CheckCallingConvAttr(const AttributeList &Attrs, CallingConv &CC, +bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, const FunctionDecl *FD) { if (Attrs.isInvalid()) return true; @@ -4301,7 +4271,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &Attrs, CallingConv &CC, return false; } - unsigned ReqArgs = Attrs.getKind() == AttributeList::AT_Pcs ? 1 : 0; + unsigned ReqArgs = Attrs.getKind() == ParsedAttr::AT_Pcs ? 1 : 0; if (!checkAttributeNumArgs(*this, Attrs, ReqArgs)) { Attrs.setInvalid(); return true; @@ -4309,23 +4279,39 @@ bool Sema::CheckCallingConvAttr(const AttributeList &Attrs, CallingConv &CC, // TODO: diagnose uses of these conventions on the wrong target. switch (Attrs.getKind()) { - case AttributeList::AT_CDecl: CC = CC_C; break; - case AttributeList::AT_FastCall: CC = CC_X86FastCall; break; - case AttributeList::AT_StdCall: CC = CC_X86StdCall; break; - case AttributeList::AT_ThisCall: CC = CC_X86ThisCall; break; - case AttributeList::AT_Pascal: CC = CC_X86Pascal; break; - case AttributeList::AT_SwiftCall: CC = CC_Swift; break; - case AttributeList::AT_VectorCall: CC = CC_X86VectorCall; break; - case AttributeList::AT_RegCall: CC = CC_X86RegCall; break; - case AttributeList::AT_MSABI: + case ParsedAttr::AT_CDecl: + CC = CC_C; + break; + case ParsedAttr::AT_FastCall: + CC = CC_X86FastCall; + break; + case ParsedAttr::AT_StdCall: + CC = CC_X86StdCall; + break; + case ParsedAttr::AT_ThisCall: + CC = CC_X86ThisCall; + break; + case ParsedAttr::AT_Pascal: + CC = CC_X86Pascal; + break; + case ParsedAttr::AT_SwiftCall: + CC = CC_Swift; + break; + case ParsedAttr::AT_VectorCall: + CC = CC_X86VectorCall; + break; + case ParsedAttr::AT_RegCall: + CC = CC_X86RegCall; + break; + case ParsedAttr::AT_MSABI: CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C : CC_Win64; break; - case AttributeList::AT_SysVABI: + case ParsedAttr::AT_SysVABI: CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_X86_64SysV : CC_C; break; - case AttributeList::AT_Pcs: { + case ParsedAttr::AT_Pcs: { StringRef StrRef; if (!checkStringLiteralArgumentAttr(Attrs, 0, StrRef)) { Attrs.setInvalid(); @@ -4343,9 +4329,15 @@ bool Sema::CheckCallingConvAttr(const AttributeList &Attrs, CallingConv &CC, Diag(Attrs.getLoc(), diag::err_invalid_pcs); return true; } - case AttributeList::AT_IntelOclBicc: CC = CC_IntelOclBicc; break; - case AttributeList::AT_PreserveMost: CC = CC_PreserveMost; break; - case AttributeList::AT_PreserveAll: CC = CC_PreserveAll; break; + case ParsedAttr::AT_IntelOclBicc: + CC = CC_IntelOclBicc; + break; + case ParsedAttr::AT_PreserveMost: + CC = CC_PreserveMost; + break; + case ParsedAttr::AT_PreserveAll: + CC = CC_PreserveAll; + break; default: llvm_unreachable("unexpected attribute kind"); } @@ -4370,39 +4362,39 @@ bool Sema::CheckCallingConvAttr(const AttributeList &Attrs, CallingConv &CC, } /// Pointer-like types in the default address space. -static bool isValidSwiftContextType(QualType type) { - if (!type->hasPointerRepresentation()) - return type->isDependentType(); - return type->getPointeeType().getAddressSpace() == LangAS::Default; +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 type) { - if (auto ptrType = type->getAs<PointerType>()) { - type = ptrType->getPointeeType(); - } else if (auto refType = type->getAs<ReferenceType>()) { - type = refType->getPointeeType(); +static bool isValidSwiftIndirectResultType(QualType Ty) { + if (const auto *PtrType = Ty->getAs<PointerType>()) { + Ty = PtrType->getPointeeType(); + } else if (const auto *RefType = Ty->getAs<ReferenceType>()) { + Ty = RefType->getPointeeType(); } else { - return type->isDependentType(); + return Ty->isDependentType(); } - return type.getAddressSpace() == LangAS::Default; + return Ty.getAddressSpace() == LangAS::Default; } /// Pointers and references to pointers in the default address space. -static bool isValidSwiftErrorResultType(QualType type) { - if (auto ptrType = type->getAs<PointerType>()) { - type = ptrType->getPointeeType(); - } else if (auto refType = type->getAs<ReferenceType>()) { - type = refType->getPointeeType(); +static bool isValidSwiftErrorResultType(QualType Ty) { + if (const auto *PtrType = Ty->getAs<PointerType>()) { + Ty = PtrType->getPointeeType(); + } else if (const auto *RefType = Ty->getAs<ReferenceType>()) { + Ty = RefType->getPointeeType(); } else { - return type->isDependentType(); + return Ty->isDependentType(); } - if (!type.getQualifiers().empty()) + if (!Ty.getQualifiers().empty()) return false; - return isValidSwiftContextType(type); + return isValidSwiftContextType(Ty); } -static void handleParameterABIAttr(Sema &S, Decl *D, const AttributeList &Attrs, +static void handleParameterABIAttr(Sema &S, Decl *D, const ParsedAttr &Attrs, ParameterABI Abi) { S.AddParameterABIAttr(Attrs.getRange(), D, Abi, Attrs.getAttributeSpellingListIndex()); @@ -4461,34 +4453,34 @@ void Sema::AddParameterABIAttr(SourceRange range, Decl *D, ParameterABI abi, /// Checks a regparm attribute, returning true if it is ill-formed and /// otherwise setting numParams to the appropriate value. -bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { - if (Attr.isInvalid()) +bool Sema::CheckRegparmAttr(const ParsedAttr &AL, unsigned &numParams) { + if (AL.isInvalid()) return true; - if (!checkAttributeNumArgs(*this, Attr, 1)) { - Attr.setInvalid(); + if (!checkAttributeNumArgs(*this, AL, 1)) { + AL.setInvalid(); return true; } uint32_t NP; - Expr *NumParamsExpr = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(*this, Attr, NumParamsExpr, NP)) { - Attr.setInvalid(); + Expr *NumParamsExpr = AL.getArgAsExpr(0); + if (!checkUInt32Argument(*this, AL, NumParamsExpr, NP)) { + AL.setInvalid(); return true; } if (Context.getTargetInfo().getRegParmMax() == 0) { - Diag(Attr.getLoc(), diag::err_attribute_regparm_wrong_platform) + Diag(AL.getLoc(), diag::err_attribute_regparm_wrong_platform) << NumParamsExpr->getSourceRange(); - Attr.setInvalid(); + AL.setInvalid(); return true; } numParams = NP; if (numParams > Context.getTargetInfo().getRegParmMax()) { - Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number) + Diag(AL.getLoc(), diag::err_attribute_regparm_invalid_number) << Context.getTargetInfo().getRegParmMax() << NumParamsExpr->getSourceRange(); - Attr.setInvalid(); + AL.setInvalid(); return true; } @@ -4500,7 +4492,7 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { // non-nullptr Expr result on success. Otherwise, it returns nullptr // and may output an error. static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E, - const CUDALaunchBoundsAttr &Attr, + const CUDALaunchBoundsAttr &AL, const unsigned Idx) { if (S.DiagnoseUnexpandedParameterPack(E)) return nullptr; @@ -4513,7 +4505,7 @@ static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E, llvm::APSInt I(64); if (!E->isIntegerConstantExpr(I, S.Context)) { S.Diag(E->getExprLoc(), diag::err_attribute_argument_n_type) - << &Attr << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange(); + << &AL << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange(); return nullptr; } // Make sure we can fit it in 32 bits. @@ -4524,7 +4516,7 @@ static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E, } if (I < 0) S.Diag(E->getExprLoc(), diag::warn_attribute_argument_n_negative) - << &Attr << Idx << E->getSourceRange(); + << &AL << Idx << E->getSourceRange(); // We may need to perform implicit conversion of the argument. InitializedEntity Entity = InitializedEntity::InitializeParameter( @@ -4554,253 +4546,232 @@ void Sema::AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads, AttrRange, Context, MaxThreads, MinBlocks, SpellingListIndex)); } -static void handleLaunchBoundsAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1) || - !checkAttributeAtMostNumArgs(S, Attr, 2)) +static void handleLaunchBoundsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1) || + !checkAttributeAtMostNumArgs(S, AL, 2)) return; - S.AddLaunchBoundsAttr(Attr.getRange(), D, Attr.getArgAsExpr(0), - Attr.getNumArgs() > 1 ? Attr.getArgAsExpr(1) : nullptr, - Attr.getAttributeSpellingListIndex()); + S.AddLaunchBoundsAttr(AL.getRange(), D, AL.getArgAsExpr(0), + AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr, + AL.getAttributeSpellingListIndex()); } static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << /* arg num = */ 1 << AANT_ArgumentIdentifier; - return; - } - - if (!checkAttributeNumArgs(S, Attr, 3)) - return; - - IdentifierInfo *ArgumentKind = Attr.getArgAsIdent(0)->Ident; - - if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionOrMethod; + const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << /* arg num = */ 1 << AANT_ArgumentIdentifier; return; } - uint64_t ArgumentIdx; - if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 2, Attr.getArgAsExpr(1), + ParamIdx ArgumentIdx; + if (!checkFunctionOrMethodParameterIndex(S, D, AL, 2, AL.getArgAsExpr(1), ArgumentIdx)) return; - uint64_t TypeTagIdx; - if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 3, Attr.getArgAsExpr(2), + ParamIdx TypeTagIdx; + if (!checkFunctionOrMethodParameterIndex(S, D, AL, 3, AL.getArgAsExpr(2), TypeTagIdx)) return; - bool IsPointer = (Attr.getName()->getName() == "pointer_with_type_tag"); + bool IsPointer = AL.getName()->getName() == "pointer_with_type_tag"; if (IsPointer) { // Ensure that buffer has a pointer type. - QualType BufferTy = getFunctionOrMethodParamType(D, ArgumentIdx); - if (!BufferTy->isPointerType()) { - S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only) - << Attr.getName() << 0; - } + unsigned ArgumentIdxAST = ArgumentIdx.getASTIndex(); + if (ArgumentIdxAST >= getFunctionOrMethodNumParams(D) || + !getFunctionOrMethodParamType(D, ArgumentIdxAST)->isPointerType()) + S.Diag(AL.getLoc(), diag::err_attribute_pointers_only) + << AL.getName() << 0; } - D->addAttr(::new (S.Context) - ArgumentWithTypeTagAttr(Attr.getRange(), S.Context, ArgumentKind, - ArgumentIdx, TypeTagIdx, IsPointer, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ArgumentWithTypeTagAttr( + AL.getRange(), S.Context, AL.getArgAsIdent(0)->Ident, ArgumentIdx, + TypeTagIdx, IsPointer, AL.getAttributeSpellingListIndex())); } static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIdentifier; + const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 1 << AANT_ArgumentIdentifier; return; } - - if (!checkAttributeNumArgs(S, Attr, 1)) + + if (!checkAttributeNumArgs(S, AL, 1)) return; if (!isa<VarDecl>(D)) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedVariable; + S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type) + << AL.getName() << ExpectedVariable; return; } - IdentifierInfo *PointerKind = Attr.getArgAsIdent(0)->Ident; + IdentifierInfo *PointerKind = AL.getArgAsIdent(0)->Ident; TypeSourceInfo *MatchingCTypeLoc = nullptr; - S.GetTypeFromParser(Attr.getMatchingCType(), &MatchingCTypeLoc); + S.GetTypeFromParser(AL.getMatchingCType(), &MatchingCTypeLoc); assert(MatchingCTypeLoc && "no type source info for attribute argument"); D->addAttr(::new (S.Context) - TypeTagForDatatypeAttr(Attr.getRange(), S.Context, PointerKind, + TypeTagForDatatypeAttr(AL.getRange(), S.Context, PointerKind, MatchingCTypeLoc, - Attr.getLayoutCompatible(), - Attr.getMustBeNull(), - Attr.getAttributeSpellingListIndex())); + AL.getLayoutCompatible(), + AL.getMustBeNull(), + AL.getAttributeSpellingListIndex())); } -static void handleXRayLogArgsAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - uint64_t ArgCount; +static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + ParamIdx ArgCount; - if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 1, Attr.getArgAsExpr(0), + if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, AL.getArgAsExpr(0), ArgCount, - true /* AllowImplicitThis*/)) + true /* CanIndexImplicitThis */)) return; - // ArgCount isn't a parameter index [0;n), it's a count [1;n] - hence + 1. - D->addAttr(::new (S.Context) - XRayLogArgsAttr(Attr.getRange(), S.Context, ++ArgCount, - Attr.getAttributeSpellingListIndex())); + // ArgCount isn't a parameter index [0;n), it's a count [1;n] + D->addAttr(::new (S.Context) XRayLogArgsAttr( + AL.getRange(), S.Context, ArgCount.getSourceIndex(), + AL.getAttributeSpellingListIndex())); } //===----------------------------------------------------------------------===// // Checker-specific attribute handlers. //===----------------------------------------------------------------------===// -static bool isValidSubjectOfNSReturnsRetainedAttribute(QualType type) { - return type->isDependentType() || - type->isObjCRetainableType(); +static bool isValidSubjectOfNSReturnsRetainedAttribute(QualType QT) { + return QT->isDependentType() || QT->isObjCRetainableType(); } -static bool isValidSubjectOfNSAttribute(Sema &S, QualType type) { - return type->isDependentType() || - type->isObjCObjectPointerType() || - S.Context.isObjCNSObjectType(type); +static bool isValidSubjectOfNSAttribute(Sema &S, QualType QT) { + return QT->isDependentType() || QT->isObjCObjectPointerType() || + S.Context.isObjCNSObjectType(QT); } -static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) { - return type->isDependentType() || - type->isPointerType() || - isValidSubjectOfNSAttribute(S, type); +static bool isValidSubjectOfCFAttribute(Sema &S, QualType QT) { + return QT->isDependentType() || QT->isPointerType() || + isValidSubjectOfNSAttribute(S, QT); } -static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - S.AddNSConsumedAttr(Attr.getRange(), D, Attr.getAttributeSpellingListIndex(), - Attr.getKind() == AttributeList::AT_NSConsumed, +static void handleNSConsumedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + S.AddNSConsumedAttr(AL.getRange(), D, AL.getAttributeSpellingListIndex(), + AL.getKind() == ParsedAttr::AT_NSConsumed, /*template instantiation*/ false); } -void Sema::AddNSConsumedAttr(SourceRange attrRange, Decl *D, - unsigned spellingIndex, bool isNSConsumed, - bool isTemplateInstantiation) { - ParmVarDecl *param = cast<ParmVarDecl>(D); - bool typeOK; +void Sema::AddNSConsumedAttr(SourceRange AttrRange, Decl *D, + unsigned SpellingIndex, bool IsNSConsumed, + bool IsTemplateInstantiation) { + const auto *Param = cast<ParmVarDecl>(D); + bool TypeOK; - if (isNSConsumed) { - typeOK = isValidSubjectOfNSAttribute(*this, param->getType()); - } else { - typeOK = isValidSubjectOfCFAttribute(*this, param->getType()); - } + if (IsNSConsumed) + TypeOK = isValidSubjectOfNSAttribute(*this, Param->getType()); + else + TypeOK = isValidSubjectOfCFAttribute(*this, Param->getType()); - if (!typeOK) { + if (!TypeOK) { // 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. - Diag(D->getLocStart(), - (isTemplateInstantiation && isNSConsumed && - getLangOpts().ObjCAutoRefCount - ? diag::err_ns_attribute_wrong_parameter_type - : diag::warn_ns_attribute_wrong_parameter_type)) - << attrRange - << (isNSConsumed ? "ns_consumed" : "cf_consumed") - << (isNSConsumed ? /*objc pointers*/ 0 : /*cf pointers*/ 1); + Diag(D->getLocStart(), (IsTemplateInstantiation && IsNSConsumed && + getLangOpts().ObjCAutoRefCount + ? diag::err_ns_attribute_wrong_parameter_type + : diag::warn_ns_attribute_wrong_parameter_type)) + << AttrRange << (IsNSConsumed ? "ns_consumed" : "cf_consumed") + << (IsNSConsumed ? /*objc pointers*/ 0 : /*cf pointers*/ 1); return; } - if (isNSConsumed) - param->addAttr(::new (Context) - NSConsumedAttr(attrRange, Context, spellingIndex)); + if (IsNSConsumed) + D->addAttr(::new (Context) + NSConsumedAttr(AttrRange, Context, SpellingIndex)); else - param->addAttr(::new (Context) - CFConsumedAttr(attrRange, Context, spellingIndex)); + D->addAttr(::new (Context) + CFConsumedAttr(AttrRange, Context, SpellingIndex)); } -bool Sema::checkNSReturnsRetainedReturnType(SourceLocation loc, - QualType type) { - if (isValidSubjectOfNSReturnsRetainedAttribute(type)) +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; + Diag(Loc, diag::warn_ns_attribute_wrong_return_type) + << "'ns_returns_retained'" << 0 << 0; return true; } static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - QualType returnType; + const ParsedAttr &AL) { + QualType ReturnType; - if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) - returnType = MD->getReturnType(); + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) + ReturnType = MD->getReturnType(); else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) && - (Attr.getKind() == AttributeList::AT_NSReturnsRetained)) + (AL.getKind() == ParsedAttr::AT_NSReturnsRetained)) return; // ignore: was handled as a type attribute - else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) - returnType = PD->getType(); - else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - returnType = FD->getReturnType(); - else if (auto *Param = dyn_cast<ParmVarDecl>(D)) { - returnType = Param->getType()->getPointeeType(); - if (returnType.isNull()) { + else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) + ReturnType = PD->getType(); + else if (const auto *FD = dyn_cast<FunctionDecl>(D)) + ReturnType = FD->getReturnType(); + else if (const auto *Param = dyn_cast<ParmVarDecl>(D)) { + ReturnType = Param->getType()->getPointeeType(); + if (ReturnType.isNull()) { S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) - << Attr.getName() << /*pointer-to-CF*/2 - << Attr.getRange(); + << AL.getName() << /*pointer-to-CF*/2 + << AL.getRange(); return; } - } else if (Attr.isUsedAsTypeAttr()) { + } else if (AL.isUsedAsTypeAttr()) { return; } else { AttributeDeclKind ExpectedDeclKind; - switch (Attr.getKind()) { + switch (AL.getKind()) { default: llvm_unreachable("invalid ownership attribute"); - case AttributeList::AT_NSReturnsRetained: - case AttributeList::AT_NSReturnsAutoreleased: - case AttributeList::AT_NSReturnsNotRetained: + case ParsedAttr::AT_NSReturnsRetained: + case ParsedAttr::AT_NSReturnsAutoreleased: + case ParsedAttr::AT_NSReturnsNotRetained: ExpectedDeclKind = ExpectedFunctionOrMethod; break; - case AttributeList::AT_CFReturnsRetained: - case AttributeList::AT_CFReturnsNotRetained: + case ParsedAttr::AT_CFReturnsRetained: + case ParsedAttr::AT_CFReturnsNotRetained: ExpectedDeclKind = ExpectedFunctionMethodOrParameter; break; } S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) - << Attr.getRange() << Attr.getName() << ExpectedDeclKind; + << AL.getRange() << AL.getName() << ExpectedDeclKind; return; } - bool typeOK; - bool cf; - switch (Attr.getKind()) { + bool TypeOK; + bool Cf; + switch (AL.getKind()) { default: llvm_unreachable("invalid ownership attribute"); - case AttributeList::AT_NSReturnsRetained: - typeOK = isValidSubjectOfNSReturnsRetainedAttribute(returnType); - cf = false; + case ParsedAttr::AT_NSReturnsRetained: + TypeOK = isValidSubjectOfNSReturnsRetainedAttribute(ReturnType); + Cf = false; break; - - case AttributeList::AT_NSReturnsAutoreleased: - case AttributeList::AT_NSReturnsNotRetained: - typeOK = isValidSubjectOfNSAttribute(S, returnType); - cf = false; + + case ParsedAttr::AT_NSReturnsAutoreleased: + case ParsedAttr::AT_NSReturnsNotRetained: + TypeOK = isValidSubjectOfNSAttribute(S, ReturnType); + Cf = false; break; - case AttributeList::AT_CFReturnsRetained: - case AttributeList::AT_CFReturnsNotRetained: - typeOK = isValidSubjectOfCFAttribute(S, returnType); - cf = true; + case ParsedAttr::AT_CFReturnsRetained: + case ParsedAttr::AT_CFReturnsNotRetained: + TypeOK = isValidSubjectOfCFAttribute(S, ReturnType); + Cf = true; break; } - if (!typeOK) { - if (Attr.isUsedAsTypeAttr()) + if (!TypeOK) { + if (AL.isUsedAsTypeAttr()) return; if (isa<ParmVarDecl>(D)) { S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) - << Attr.getName() << /*pointer-to-CF*/2 - << Attr.getRange(); + << AL.getName() << /*pointer-to-CF*/2 + << AL.getRange(); } else { // Needs to be kept in sync with warn_ns_attribute_wrong_return_type. enum : unsigned { @@ -4813,43 +4784,43 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, else if (isa<ObjCPropertyDecl>(D)) SubjectKind = Property; S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type) - << Attr.getName() << SubjectKind << cf - << Attr.getRange(); + << AL.getName() << SubjectKind << Cf + << AL.getRange(); } return; } - switch (Attr.getKind()) { + switch (AL.getKind()) { default: llvm_unreachable("invalid ownership attribute"); - case AttributeList::AT_NSReturnsAutoreleased: + case ParsedAttr::AT_NSReturnsAutoreleased: D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_CFReturnsNotRetained: + case ParsedAttr::AT_CFReturnsNotRetained: D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_NSReturnsNotRetained: + case ParsedAttr::AT_NSReturnsNotRetained: D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_CFReturnsRetained: + case ParsedAttr::AT_CFReturnsRetained: D->addAttr(::new (S.Context) CFReturnsRetainedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_NSReturnsRetained: + case ParsedAttr::AT_NSReturnsRetained: D->addAttr(::new (S.Context) NSReturnsRetainedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; }; } static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, - const AttributeList &Attrs) { + const ParsedAttr &Attrs) { const int EP_ObjCMethod = 1; const int EP_ObjCProperty = 2; - + SourceLocation loc = Attrs.getLoc(); QualType resultType; if (isa<ObjCMethodDecl>(D)) @@ -4874,116 +4845,91 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, } static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, - const AttributeList &Attrs) { - ObjCMethodDecl *method = cast<ObjCMethodDecl>(D); - - DeclContext *DC = method->getDeclContext(); - if (const ObjCProtocolDecl *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) { + const ParsedAttr &Attrs) { + const auto *Method = cast<ObjCMethodDecl>(D); + + const DeclContext *DC = Method->getDeclContext(); + if (const auto *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) { S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol) - << Attrs.getName() << 0; + << Attrs.getName() << 0; S.Diag(PDecl->getLocation(), diag::note_protocol_decl); return; } - if (method->getMethodFamily() == OMF_dealloc) { + if (Method->getMethodFamily() == OMF_dealloc) { S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol) - << Attrs.getName() << 1; + << Attrs.getName() << 1; return; } - - method->addAttr(::new (S.Context) - ObjCRequiresSuperAttr(Attrs.getRange(), S.Context, - Attrs.getAttributeSpellingListIndex())); -} -static void handleCFAuditedTransferAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<CFUnknownTransferAttr>(S, D, Attr.getRange(), - Attr.getName())) - return; - - D->addAttr(::new (S.Context) - CFAuditedTransferAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleCFUnknownTransferAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<CFAuditedTransferAttr>(S, D, Attr.getRange(), - Attr.getName())) - return; - - D->addAttr(::new (S.Context) - CFUnknownTransferAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ObjCRequiresSuperAttr( + Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex())); } -static void handleObjCBridgeAttr(Sema &S, Scope *Sc, Decl *D, - const AttributeList &Attr) { - IdentifierLoc * Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; +static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr; if (!Parm) { - S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0; + S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << AL.getName() << 0; return; } // Typedefs only allow objc_bridge(id) and have some additional checking. - if (auto TD = dyn_cast<TypedefNameDecl>(D)) { + if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { if (!Parm->Ident->isStr("id")) { - S.Diag(Attr.getLoc(), diag::err_objc_attr_typedef_not_id) - << Attr.getName(); + S.Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_id) + << AL.getName(); return; } // Only allow 'cv void *'. QualType T = TD->getUnderlyingType(); if (!T->isVoidPointerType()) { - S.Diag(Attr.getLoc(), diag::err_objc_attr_typedef_not_void_pointer); + S.Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_void_pointer); return; } } - + D->addAttr(::new (S.Context) - ObjCBridgeAttr(Attr.getRange(), S.Context, Parm->Ident, - Attr.getAttributeSpellingListIndex())); + ObjCBridgeAttr(AL.getRange(), S.Context, Parm->Ident, + AL.getAttributeSpellingListIndex())); } -static void handleObjCBridgeMutableAttr(Sema &S, Scope *Sc, Decl *D, - const AttributeList &Attr) { - IdentifierLoc * Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; +static void handleObjCBridgeMutableAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr; if (!Parm) { - S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0; + S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << AL.getName() << 0; return; } - + D->addAttr(::new (S.Context) - ObjCBridgeMutableAttr(Attr.getRange(), S.Context, Parm->Ident, - Attr.getAttributeSpellingListIndex())); + ObjCBridgeMutableAttr(AL.getRange(), S.Context, Parm->Ident, + AL.getAttributeSpellingListIndex())); } -static void handleObjCBridgeRelatedAttr(Sema &S, Scope *Sc, Decl *D, - const AttributeList &Attr) { +static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { IdentifierInfo *RelatedClass = - Attr.isArgIdent(0) ? Attr.getArgAsIdent(0)->Ident : nullptr; + AL.isArgIdent(0) ? AL.getArgAsIdent(0)->Ident : nullptr; if (!RelatedClass) { - S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0; + S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << AL.getName() << 0; return; } IdentifierInfo *ClassMethod = - Attr.getArgAsIdent(1) ? Attr.getArgAsIdent(1)->Ident : nullptr; + AL.getArgAsIdent(1) ? AL.getArgAsIdent(1)->Ident : nullptr; IdentifierInfo *InstanceMethod = - Attr.getArgAsIdent(2) ? Attr.getArgAsIdent(2)->Ident : nullptr; + AL.getArgAsIdent(2) ? AL.getArgAsIdent(2)->Ident : nullptr; D->addAttr(::new (S.Context) - ObjCBridgeRelatedAttr(Attr.getRange(), S.Context, RelatedClass, + ObjCBridgeRelatedAttr(AL.getRange(), S.Context, RelatedClass, ClassMethod, InstanceMethod, - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } static void handleObjCDesignatedInitializer(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { ObjCInterfaceDecl *IFace; - if (ObjCCategoryDecl *CatDecl = - dyn_cast<ObjCCategoryDecl>(D->getDeclContext())) + if (auto *CatDecl = dyn_cast<ObjCCategoryDecl>(D->getDeclContext())) IFace = CatDecl->getClassInterface(); else IFace = cast<ObjCInterfaceDecl>(D->getDeclContext()); @@ -4993,29 +4939,28 @@ static void handleObjCDesignatedInitializer(Sema &S, Decl *D, IFace->setHasDesignatedInitializers(); D->addAttr(::new (S.Context) - ObjCDesignatedInitializerAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ObjCDesignatedInitializerAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleObjCRuntimeName(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleObjCRuntimeName(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef MetaDataName; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, MetaDataName)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, MetaDataName)) return; D->addAttr(::new (S.Context) - ObjCRuntimeNameAttr(Attr.getRange(), S.Context, + ObjCRuntimeNameAttr(AL.getRange(), S.Context, MetaDataName, - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } // 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 AttributeList &Attr) { +static void handleObjCBoxable(Sema &S, Decl *D, const ParsedAttr &AL) { bool notify = false; - RecordDecl *RD = dyn_cast<RecordDecl>(D); + auto *RD = dyn_cast<RecordDecl>(D); if (RD && RD->getDefinition()) { RD = RD->getDefinition(); notify = true; @@ -5023,8 +4968,8 @@ static void handleObjCBoxable(Sema &S, Decl *D, const AttributeList &Attr) { if (RD) { ObjCBoxableAttr *BoxableAttr = ::new (S.Context) - ObjCBoxableAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex()); + ObjCBoxableAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex()); RD->addAttr(BoxableAttr); if (notify) { // we need to notify ASTReader/ASTWriter about @@ -5035,36 +4980,35 @@ static void handleObjCBoxable(Sema &S, Decl *D, const AttributeList &Attr) { } } -static void handleObjCOwnershipAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleObjCOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (hasDeclarator(D)) return; S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) - << Attr.getRange() << Attr.getName() << ExpectedVariable; + << AL.getRange() << AL.getName() << ExpectedVariable; } static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - ValueDecl *vd = cast<ValueDecl>(D); - QualType type = vd->getType(); + const ParsedAttr &AL) { + const auto *VD = cast<ValueDecl>(D); + QualType QT = VD->getType(); - if (!type->isDependentType() && - !type->isObjCLifetimeType()) { - S.Diag(Attr.getLoc(), diag::err_objc_precise_lifetime_bad_type) - << type; + if (!QT->isDependentType() && + !QT->isObjCLifetimeType()) { + S.Diag(AL.getLoc(), diag::err_objc_precise_lifetime_bad_type) + << QT; return; } - Qualifiers::ObjCLifetime lifetime = type.getObjCLifetime(); + 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 && !type->isDependentType()) - lifetime = type->getObjCARCImplicitLifetime(); + if (Lifetime == Qualifiers::OCL_None && !QT->isDependentType()) + Lifetime = QT->getObjCARCImplicitLifetime(); - switch (lifetime) { + switch (Lifetime) { case Qualifiers::OCL_None: - assert(type->isDependentType() && + assert(QT->isDependentType() && "didn't infer lifetime for non-dependent type?"); break; @@ -5074,14 +5018,14 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, case Qualifiers::OCL_ExplicitNone: case Qualifiers::OCL_Autoreleasing: - S.Diag(Attr.getLoc(), diag::warn_objc_precise_lifetime_meaningless) - << (lifetime == Qualifiers::OCL_Autoreleasing); + S.Diag(AL.getLoc(), diag::warn_objc_precise_lifetime_meaningless) + << (Lifetime == Qualifiers::OCL_Autoreleasing); break; } D->addAttr(::new (S.Context) - ObjCPreciseLifetimeAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ObjCPreciseLifetimeAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } //===----------------------------------------------------------------------===// @@ -5101,16 +5045,16 @@ UuidAttr *Sema::mergeUuidAttr(Decl *D, SourceRange Range, return ::new (Context) UuidAttr(Range, Context, Uuid, AttrSpellingListIndex); } -static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.LangOpts.CPlusPlus) { - S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang) - << Attr.getName() << AttributeLangSupport::C; + S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) + << AL.getName() << AttributeLangSupport::C; return; } StringRef StrRef; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, StrRef, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, StrRef, &LiteralLoc)) return; // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or @@ -5142,162 +5086,158 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { // separating attributes nor of the [ and the ] are in the AST. // Cf "SourceLocations of attribute list delimiters - [[ ... , ... ]] etc" // on cfe-dev. - if (Attr.isMicrosoftAttribute()) // Check for [uuid(...)] spelling. - S.Diag(Attr.getLoc(), diag::warn_atl_uuid_deprecated); + if (AL.isMicrosoftAttribute()) // Check for [uuid(...)] spelling. + S.Diag(AL.getLoc(), diag::warn_atl_uuid_deprecated); - UuidAttr *UA = S.mergeUuidAttr(D, Attr.getRange(), - Attr.getAttributeSpellingListIndex(), StrRef); + UuidAttr *UA = S.mergeUuidAttr(D, AL.getRange(), + AL.getAttributeSpellingListIndex(), StrRef); if (UA) D->addAttr(UA); } -static void handleMSInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.LangOpts.CPlusPlus) { - S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang) - << Attr.getName() << AttributeLangSupport::C; + S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) + << AL.getName() << AttributeLangSupport::C; return; } MSInheritanceAttr *IA = S.mergeMSInheritanceAttr( - D, Attr.getRange(), /*BestCase=*/true, - Attr.getAttributeSpellingListIndex(), - (MSInheritanceAttr::Spelling)Attr.getSemanticSpelling()); + D, AL.getRange(), /*BestCase=*/true, + AL.getAttributeSpellingListIndex(), + (MSInheritanceAttr::Spelling)AL.getSemanticSpelling()); if (IA) { D->addAttr(IA); S.Consumer.AssignInheritanceModel(cast<CXXRecordDecl>(D)); } } -static void handleDeclspecThreadAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - VarDecl *VD = cast<VarDecl>(D); +static void handleDeclspecThreadAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + const auto *VD = cast<VarDecl>(D); if (!S.Context.getTargetInfo().isTLSSupported()) { - S.Diag(Attr.getLoc(), diag::err_thread_unsupported); + S.Diag(AL.getLoc(), diag::err_thread_unsupported); return; } if (VD->getTSCSpec() != TSCS_unspecified) { - S.Diag(Attr.getLoc(), diag::err_declspec_thread_on_thread_variable); + S.Diag(AL.getLoc(), diag::err_declspec_thread_on_thread_variable); return; } if (VD->hasLocalStorage()) { - S.Diag(Attr.getLoc(), diag::err_thread_non_global) << "__declspec(thread)"; + S.Diag(AL.getLoc(), diag::err_thread_non_global) << "__declspec(thread)"; return; } - VD->addAttr(::new (S.Context) ThreadAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ThreadAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleAbiTagAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { SmallVector<StringRef, 4> Tags; - for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) { + for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { StringRef Tag; - if (!S.checkStringLiteralArgumentAttr(Attr, I, Tag)) + if (!S.checkStringLiteralArgumentAttr(AL, I, Tag)) return; Tags.push_back(Tag); } if (const auto *NS = dyn_cast<NamespaceDecl>(D)) { if (!NS->isInline()) { - S.Diag(Attr.getLoc(), diag::warn_attr_abi_tag_namespace) << 0; + S.Diag(AL.getLoc(), diag::warn_attr_abi_tag_namespace) << 0; return; } if (NS->isAnonymousNamespace()) { - S.Diag(Attr.getLoc(), diag::warn_attr_abi_tag_namespace) << 1; + S.Diag(AL.getLoc(), diag::warn_attr_abi_tag_namespace) << 1; return; } - if (Attr.getNumArgs() == 0) + if (AL.getNumArgs() == 0) Tags.push_back(NS->getName()); - } else if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + } else if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; // Store tags sorted and without duplicates. - std::sort(Tags.begin(), Tags.end()); + llvm::sort(Tags.begin(), Tags.end()); Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end()); D->addAttr(::new (S.Context) - AbiTagAttr(Attr.getRange(), S.Context, Tags.data(), Tags.size(), - Attr.getAttributeSpellingListIndex())); + AbiTagAttr(AL.getRange(), S.Context, Tags.data(), Tags.size(), + AL.getAttributeSpellingListIndex())); } -static void handleARMInterruptAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Check the attribute arguments. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) - << Attr.getName() << 1; + if (AL.getNumArgs() > 1) { + S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) + << AL.getName() << 1; return; } StringRef Str; SourceLocation ArgLoc; - if (Attr.getNumArgs() == 0) + if (AL.getNumArgs() == 0) Str = ""; - else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc)) + else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) return; ARMInterruptAttr::InterruptType Kind; if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << Attr.getName() << Str << ArgLoc; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << Str << ArgLoc; return; } - unsigned Index = Attr.getAttributeSpellingListIndex(); + unsigned Index = AL.getAttributeSpellingListIndex(); D->addAttr(::new (S.Context) - ARMInterruptAttr(Attr.getLoc(), S.Context, Kind, Index)); + ARMInterruptAttr(AL.getLoc(), S.Context, Kind, Index)); } -static void handleMSP430InterruptAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 1)) +static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeNumArgs(S, AL, 1)) return; - if (!Attr.isArgExpr(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName() + if (!AL.isArgExpr(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << AL.getName() << AANT_ArgumentIntegerConstant; - return; + return; } // FIXME: Check for decl - it should be void ()(void). - Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); + Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0)); llvm::APSInt NumParams(32); if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentIntegerConstant + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL.getName() << AANT_ArgumentIntegerConstant << NumParamsExpr->getSourceRange(); return; } unsigned Num = NumParams.getLimitedValue(255); if ((Num & 1) || Num > 30) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) - << Attr.getName() << (int)NumParams.getSExtValue() + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL.getName() << (int)NumParams.getSExtValue() << NumParamsExpr->getSourceRange(); return; } D->addAttr(::new (S.Context) - MSP430InterruptAttr(Attr.getLoc(), S.Context, Num, - Attr.getAttributeSpellingListIndex())); + MSP430InterruptAttr(AL.getLoc(), S.Context, Num, + AL.getAttributeSpellingListIndex())); D->addAttr(UsedAttr::CreateImplicit(S.Context)); } -static void handleMipsInterruptAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Only one optional argument permitted. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) - << Attr.getName() << 1; + if (AL.getNumArgs() > 1) { + S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) + << AL.getName() << 1; return; } StringRef Str; SourceLocation ArgLoc; - if (Attr.getNumArgs() == 0) + if (AL.getNumArgs() == 0) Str = ""; - else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc)) + else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) return; // Semantic checks for a function with the 'interrupt' attribute for MIPS: @@ -5327,23 +5267,22 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, return; } - if (checkAttrMutualExclusion<Mips16Attr>(S, D, Attr.getRange(), - Attr.getName())) + if (checkAttrMutualExclusion<Mips16Attr>(S, D, AL.getRange(), + AL.getName())) return; MipsInterruptAttr::InterruptType Kind; if (!MipsInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << Attr.getName() << "'" + std::string(Str) + "'"; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << "'" + std::string(Str) + "'"; return; } D->addAttr(::new (S.Context) MipsInterruptAttr( - Attr.getLoc(), S.Context, Kind, Attr.getAttributeSpellingListIndex())); + AL.getLoc(), S.Context, Kind, AL.getAttributeSpellingListIndex())); } -static void handleAnyX86InterruptAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +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. @@ -5353,8 +5292,8 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, if (!isFunctionOrMethod(D) || !hasFunctionProto(D) || isInstanceMethod(D) || CXXMethodDecl::isStaticOverloadedOperator( cast<NamedDecl>(D)->getDeclName().getCXXOverloadedOperator())) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionWithProtoType; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedFunctionWithProtoType; return; } // Interrupt handler must have void return type. @@ -5404,182 +5343,241 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, return; } D->addAttr(::new (S.Context) AnyX86InterruptAttr( - Attr.getLoc(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getLoc(), S.Context, AL.getAttributeSpellingListIndex())); D->addAttr(UsedAttr::CreateImplicit(S.Context)); } -static void handleAVRInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAVRInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) << "'interrupt'" << ExpectedFunction; return; } - if (!checkAttributeNumArgs(S, Attr, 0)) + if (!checkAttributeNumArgs(S, AL, 0)) return; - handleSimpleAttribute<AVRInterruptAttr>(S, D, Attr); + handleSimpleAttribute<AVRInterruptAttr>(S, D, AL); } -static void handleAVRSignalAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) << "'signal'" << ExpectedFunction; return; } - if (!checkAttributeNumArgs(S, Attr, 0)) + if (!checkAttributeNumArgs(S, AL, 0)) return; - handleSimpleAttribute<AVRSignalAttr>(S, D, Attr); + handleSimpleAttribute<AVRSignalAttr>(S, D, AL); } -static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { + +static void handleRISCVInterruptAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + // Warn about repeated attributes. + if (const auto *A = D->getAttr<RISCVInterruptAttr>()) { + S.Diag(AL.getRange().getBegin(), + diag::warn_riscv_repeated_interrupt_attribute); + S.Diag(A->getLocation(), diag::note_riscv_repeated_interrupt_attribute); + return; + } + + // Check the attribute argument. Argument is optional. + if (!checkAttributeAtMostNumArgs(S, AL, 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) + << "'interrupt'" << ExpectedFunction; + return; + } + + if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) { + S.Diag(D->getLocation(), diag::warn_riscv_interrupt_attribute) << 0; + return; + } + + if (!getFunctionOrMethodResultType(D)->isVoidType()) { + S.Diag(D->getLocation(), diag::warn_riscv_interrupt_attribute) << 1; + return; + } + + RISCVInterruptAttr::InterruptType Kind; + if (!RISCVInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << Str << ArgLoc; + return; + } + + D->addAttr(::new (S.Context) RISCVInterruptAttr( + AL.getLoc(), S.Context, Kind, AL.getAttributeSpellingListIndex())); +} + +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, Attr); + handleMSP430InterruptAttr(S, D, AL); break; case llvm::Triple::mipsel: case llvm::Triple::mips: - handleMipsInterruptAttr(S, D, Attr); + handleMipsInterruptAttr(S, D, AL); break; case llvm::Triple::x86: case llvm::Triple::x86_64: - handleAnyX86InterruptAttr(S, D, Attr); + handleAnyX86InterruptAttr(S, D, AL); break; case llvm::Triple::avr: - handleAVRInterruptAttr(S, D, Attr); + handleAVRInterruptAttr(S, D, AL); + break; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + handleRISCVInterruptAttr(S, D, AL); break; default: - handleARMInterruptAttr(S, D, Attr); + handleARMInterruptAttr(S, D, AL); break; } } static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { uint32_t Min = 0; - Expr *MinExpr = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(S, Attr, MinExpr, Min)) + Expr *MinExpr = AL.getArgAsExpr(0); + if (!checkUInt32Argument(S, AL, MinExpr, Min)) return; uint32_t Max = 0; - Expr *MaxExpr = Attr.getArgAsExpr(1); - if (!checkUInt32Argument(S, Attr, MaxExpr, Max)) + Expr *MaxExpr = AL.getArgAsExpr(1); + if (!checkUInt32Argument(S, AL, MaxExpr, Max)) return; if (Min == 0 && Max != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_invalid) - << Attr.getName() << 0; + S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) + << AL.getName() << 0; return; } if (Min > Max) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_invalid) - << Attr.getName() << 1; + S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) + << AL.getName() << 1; return; } D->addAttr(::new (S.Context) - AMDGPUFlatWorkGroupSizeAttr(Attr.getLoc(), S.Context, Min, Max, - Attr.getAttributeSpellingListIndex())); + AMDGPUFlatWorkGroupSizeAttr(AL.getLoc(), S.Context, Min, Max, + AL.getAttributeSpellingListIndex())); } -static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t Min = 0; - Expr *MinExpr = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(S, Attr, MinExpr, Min)) + Expr *MinExpr = AL.getArgAsExpr(0); + if (!checkUInt32Argument(S, AL, MinExpr, Min)) return; uint32_t Max = 0; - if (Attr.getNumArgs() == 2) { - Expr *MaxExpr = Attr.getArgAsExpr(1); - if (!checkUInt32Argument(S, Attr, MaxExpr, Max)) + if (AL.getNumArgs() == 2) { + Expr *MaxExpr = AL.getArgAsExpr(1); + if (!checkUInt32Argument(S, AL, MaxExpr, Max)) return; } if (Min == 0 && Max != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_invalid) - << Attr.getName() << 0; + S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) + << AL.getName() << 0; return; } if (Max != 0 && Min > Max) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_invalid) - << Attr.getName() << 1; + S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) + << AL.getName() << 1; return; } D->addAttr(::new (S.Context) - AMDGPUWavesPerEUAttr(Attr.getLoc(), S.Context, Min, Max, - Attr.getAttributeSpellingListIndex())); + AMDGPUWavesPerEUAttr(AL.getLoc(), S.Context, Min, Max, + AL.getAttributeSpellingListIndex())); } -static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t NumSGPR = 0; - Expr *NumSGPRExpr = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(S, Attr, NumSGPRExpr, NumSGPR)) + Expr *NumSGPRExpr = AL.getArgAsExpr(0); + if (!checkUInt32Argument(S, AL, NumSGPRExpr, NumSGPR)) return; D->addAttr(::new (S.Context) - AMDGPUNumSGPRAttr(Attr.getLoc(), S.Context, NumSGPR, - Attr.getAttributeSpellingListIndex())); + AMDGPUNumSGPRAttr(AL.getLoc(), S.Context, NumSGPR, + AL.getAttributeSpellingListIndex())); } -static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t NumVGPR = 0; - Expr *NumVGPRExpr = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(S, Attr, NumVGPRExpr, NumVGPR)) + Expr *NumVGPRExpr = AL.getArgAsExpr(0); + if (!checkUInt32Argument(S, AL, NumVGPRExpr, NumVGPR)) return; D->addAttr(::new (S.Context) - AMDGPUNumVGPRAttr(Attr.getLoc(), S.Context, NumVGPR, - Attr.getAttributeSpellingListIndex())); + AMDGPUNumVGPRAttr(AL.getLoc(), S.Context, NumVGPR, + AL.getAttributeSpellingListIndex())); } static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D, - const AttributeList& Attr) { + 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. - ValueDecl *VD = dyn_cast<ValueDecl>(D); + const auto *VD = dyn_cast<ValueDecl>(D); if (VD && VD->getType()->isFunctionPointerType()) return; // Also don't warn on function pointer typedefs. - TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D); + const auto *TD = dyn_cast<TypedefNameDecl>(D); if (TD && (TD->getUnderlyingType()->isFunctionPointerType() || TD->getUnderlyingType()->isFunctionType())) return; // Attribute can only be applied to function types. if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << /* function */0; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedFunction; return; } D->addAttr(::new (S.Context) - X86ForceAlignArgPointerAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + X86ForceAlignArgPointerAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleLayoutVersion(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleLayoutVersion(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t Version; - Expr *VersionExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); - if (!checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), Version)) + Expr *VersionExpr = static_cast<Expr *>(AL.getArgAsExpr(0)); + if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Version)) return; // TODO: Investigate what happens with the next major version of MSVC. if (Version != LangOptions::MSVC2015) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) - << Attr.getName() << Version << VersionExpr->getSourceRange(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL.getName() << Version << VersionExpr->getSourceRange(); return; } D->addAttr(::new (S.Context) - LayoutVersionAttr(Attr.getRange(), S.Context, Version, - Attr.getAttributeSpellingListIndex())); + LayoutVersionAttr(AL.getRange(), S.Context, Version, + AL.getAttributeSpellingListIndex())); } DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range, @@ -5608,7 +5606,7 @@ DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range, return ::new (Context) DLLExportAttr(Range, Context, AttrSpellingListIndex); } -static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) { +static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) { if (isa<ClassTemplatePartialSpecializationDecl>(D) && S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored) @@ -5616,8 +5614,8 @@ static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) { return; } - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - if (FD->isInlined() && A.getKind() == AttributeList::AT_DLLImport && + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isInlined() && A.getKind() == ParsedAttr::AT_DLLImport && !S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { // MinGW doesn't allow dllimport on inline functions. S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored_on_inline) @@ -5626,7 +5624,7 @@ static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) { } } - if (auto *MD = dyn_cast<CXXMethodDecl>(D)) { + if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { if (S.Context.getTargetInfo().getCXXABI().isMicrosoft() && MD->getParent()->isLambda()) { S.Diag(A.getRange().getBegin(), diag::err_attribute_dll_lambda) << A.getName(); @@ -5635,7 +5633,7 @@ static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) { } unsigned Index = A.getAttributeSpellingListIndex(); - Attr *NewAttr = A.getKind() == AttributeList::AT_DLLExport + Attr *NewAttr = A.getKind() == ParsedAttr::AT_DLLExport ? (Attr *)S.mergeDLLExportAttr(D, A.getRange(), Index) : (Attr *)S.mergeDLLImportAttr(D, A.getRange(), Index); if (NewAttr) @@ -5655,7 +5653,7 @@ Sema::mergeMSInheritanceAttr(Decl *D, SourceRange Range, bool BestCase, D->dropAttr<MSInheritanceAttr>(); } - CXXRecordDecl *RD = cast<CXXRecordDecl>(D); + auto *RD = cast<CXXRecordDecl>(D); if (RD->hasDefinition()) { if (checkMSInheritanceAttrOnDefinition(RD, Range, BestCase, SemanticSpelling)) { @@ -5678,7 +5676,7 @@ Sema::mergeMSInheritanceAttr(Decl *D, SourceRange Range, bool BestCase, MSInheritanceAttr(Range, Context, BestCase, AttrSpellingListIndex); } -static void handleCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // The capability attributes take a single string parameter for the name of // the capability they represent. The lockable attribute does not take any // parameters. However, semantically, both attributes represent the same @@ -5689,8 +5687,8 @@ static void handleCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { // literal will be considered a "mutex." StringRef N("mutex"); SourceLocation LiteralLoc; - if (Attr.getKind() == AttributeList::AT_Capability && - !S.checkStringLiteralArgumentAttr(Attr, 0, N, &LiteralLoc)) + if (AL.getKind() == ParsedAttr::AT_Capability && + !S.checkStringLiteralArgumentAttr(AL, 0, N, &LiteralLoc)) return; // Currently, there are only two names allowed for a capability: role and @@ -5698,80 +5696,79 @@ static void handleCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!N.equals_lower("mutex") && !N.equals_lower("role")) S.Diag(LiteralLoc, diag::warn_invalid_capability_name) << N; - D->addAttr(::new (S.Context) CapabilityAttr(Attr.getRange(), S.Context, N, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) CapabilityAttr(AL.getRange(), S.Context, N, + AL.getAttributeSpellingListIndex())); } -static void handleAssertCapabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleAssertCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { SmallVector<Expr*, 1> Args; - if (!checkLockFunAttrCommon(S, D, Attr, Args)) + if (!checkLockFunAttrCommon(S, D, AL, Args)) return; - D->addAttr(::new (S.Context) AssertCapabilityAttr(Attr.getRange(), S.Context, + D->addAttr(::new (S.Context) AssertCapabilityAttr(AL.getRange(), S.Context, Args.data(), Args.size(), - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } static void handleAcquireCapabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { SmallVector<Expr*, 1> Args; - if (!checkLockFunAttrCommon(S, D, Attr, Args)) + if (!checkLockFunAttrCommon(S, D, AL, Args)) return; - D->addAttr(::new (S.Context) AcquireCapabilityAttr(Attr.getRange(), + D->addAttr(::new (S.Context) AcquireCapabilityAttr(AL.getRange(), S.Context, Args.data(), Args.size(), - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } static void handleTryAcquireCapabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { SmallVector<Expr*, 2> Args; - if (!checkTryLockFunAttrCommon(S, D, Attr, Args)) + if (!checkTryLockFunAttrCommon(S, D, AL, Args)) return; - D->addAttr(::new (S.Context) TryAcquireCapabilityAttr(Attr.getRange(), + D->addAttr(::new (S.Context) TryAcquireCapabilityAttr(AL.getRange(), S.Context, - Attr.getArgAsExpr(0), + AL.getArgAsExpr(0), Args.data(), Args.size(), - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } static void handleReleaseCapabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { // Check that all arguments are lockable objects. SmallVector<Expr *, 1> Args; - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 0, true); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 0, true); D->addAttr(::new (S.Context) ReleaseCapabilityAttr( - Attr.getRange(), S.Context, Args.data(), Args.size(), - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, Args.data(), Args.size(), + AL.getAttributeSpellingListIndex())); } static void handleRequiresCapabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; // check that all arguments are lockable objects SmallVector<Expr*, 1> Args; - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args); if (Args.empty()) return; RequiresCapabilityAttr *RCA = ::new (S.Context) - RequiresCapabilityAttr(Attr.getRange(), S.Context, Args.data(), - Args.size(), Attr.getAttributeSpellingListIndex()); + RequiresCapabilityAttr(AL.getRange(), S.Context, Args.data(), + Args.size(), AL.getAttributeSpellingListIndex()); D->addAttr(RCA); } -static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (auto *NSD = dyn_cast<NamespaceDecl>(D)) { +static void handleDeprecatedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (const auto *NSD = dyn_cast<NamespaceDecl>(D)) { if (NSD->isAnonymousNamespace()) { - S.Diag(Attr.getLoc(), diag::warn_deprecated_anonymous_namespace); + S.Diag(AL.getLoc(), diag::warn_deprecated_anonymous_namespace); // Do not want to attach the attribute to the namespace because that will // cause confusing diagnostic reports for uses of declarations within the // namespace. @@ -5781,25 +5778,25 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Handle the cases where the attribute has a text message. StringRef Str, Replacement; - if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0) && - !S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (AL.isArgExpr(0) && AL.getArgAsExpr(0) && + !S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; // Only support a single optional message for Declspec and CXX11. - if (Attr.isDeclspecAttribute() || Attr.isCXX11Attribute()) - checkAttributeAtMostNumArgs(S, Attr, 1); - else if (Attr.isArgExpr(1) && Attr.getArgAsExpr(1) && - !S.checkStringLiteralArgumentAttr(Attr, 1, Replacement)) + if (AL.isDeclspecAttribute() || AL.isCXX11Attribute()) + checkAttributeAtMostNumArgs(S, AL, 1); + else if (AL.isArgExpr(1) && AL.getArgAsExpr(1) && + !S.checkStringLiteralArgumentAttr(AL, 1, Replacement)) return; if (!S.getLangOpts().CPlusPlus14) - if (Attr.isCXX11Attribute() && - !(Attr.hasScope() && Attr.getScopeName()->isStr("gnu"))) - S.Diag(Attr.getLoc(), diag::ext_cxx14_attr) << Attr.getName(); + if (AL.isCXX11Attribute() && + !(AL.hasScope() && AL.getScopeName()->isStr("gnu"))) + S.Diag(AL.getLoc(), diag::ext_cxx14_attr) << AL.getName(); D->addAttr(::new (S.Context) - DeprecatedAttr(Attr.getRange(), S.Context, Str, Replacement, - Attr.getAttributeSpellingListIndex())); + DeprecatedAttr(AL.getRange(), S.Context, Str, Replacement, + AL.getAttributeSpellingListIndex())); } static bool isGlobalVar(const Decl *D) { @@ -5808,35 +5805,35 @@ static bool isGlobalVar(const Decl *D) { return false; } -static void handleNoSanitizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) +static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; std::vector<StringRef> Sanitizers; - for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) { + for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { StringRef SanitizerName; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(Attr, I, SanitizerName, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(AL, I, SanitizerName, &LiteralLoc)) return; if (parseSanitizerValue(SanitizerName, /*AllowGroups=*/true) == 0) 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) - << Attr.getName() << ExpectedFunctionOrMethod; + << AL.getName() << ExpectedFunctionOrMethod; Sanitizers.push_back(SanitizerName); } D->addAttr(::new (S.Context) NoSanitizeAttr( - Attr.getRange(), S.Context, Sanitizers.data(), Sanitizers.size(), - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, Sanitizers.data(), Sanitizers.size(), + AL.getAttributeSpellingListIndex())); } static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - StringRef AttrName = Attr.getName()->getName(); + const ParsedAttr &AL) { + StringRef AttrName = AL.getName()->getName(); normalizeName(AttrName); StringRef SanitizerName = llvm::StringSwitch<StringRef>(AttrName) .Case("no_address_safety_analysis", "address") @@ -5845,77 +5842,78 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, .Case("no_sanitize_memory", "memory"); if (isGlobalVar(D) && SanitizerName != "address") S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunction; + << AL.getName() << ExpectedFunction; D->addAttr(::new (S.Context) - NoSanitizeAttr(Attr.getRange(), S.Context, &SanitizerName, 1, - Attr.getAttributeSpellingListIndex())); + NoSanitizeAttr(AL.getRange(), S.Context, &SanitizerName, 1, + AL.getAttributeSpellingListIndex())); } -static void handleInternalLinkageAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleInternalLinkageAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (InternalLinkageAttr *Internal = - S.mergeInternalLinkageAttr(D, Attr.getRange(), Attr.getName(), - Attr.getAttributeSpellingListIndex())) + S.mergeInternalLinkageAttr(D, AL.getRange(), AL.getName(), + AL.getAttributeSpellingListIndex())) D->addAttr(Internal); } -static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (S.LangOpts.OpenCLVersion != 200) - S.Diag(Attr.getLoc(), diag::err_attribute_requires_opencl_version) - << Attr.getName() << "2.0" << 0; + S.Diag(AL.getLoc(), diag::err_attribute_requires_opencl_version) + << AL.getName() << "2.0" << 0; else - S.Diag(Attr.getLoc(), diag::warn_opencl_attr_deprecated_ignored) - << Attr.getName() << "2.0"; + S.Diag(AL.getLoc(), diag::warn_opencl_attr_deprecated_ignored) + << AL.getName() << "2.0"; } /// Handles semantic checking for features that are common to all attributes, /// such as checking whether a parameter was properly specified, or the correct /// number of arguments were passed, etc. -static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D, - const AttributeList &Attr) { +static bool handleCommonAttributeFeatures(Sema &S, Decl *D, + const ParsedAttr &AL) { // Several attributes carry different semantics than the parsing requires, so // those are opted out of the common argument checks. // // We also bail on unknown and ignored attributes because those are handled // as part of the target-specific handling logic. - if (Attr.getKind() == AttributeList::UnknownAttribute) + if (AL.getKind() == ParsedAttr::UnknownAttribute) return false; // Check whether the attribute requires specific language extensions to be // enabled. - if (!Attr.diagnoseLangOpts(S)) + if (!AL.diagnoseLangOpts(S)) return true; // Check whether the attribute appertains to the given subject. - if (!Attr.diagnoseAppertainsTo(S, D)) + if (!AL.diagnoseAppertainsTo(S, D)) return true; - if (Attr.hasCustomParsing()) + if (AL.hasCustomParsing()) return false; - if (Attr.getMinArgs() == Attr.getMaxArgs()) { + if (AL.getMinArgs() == AL.getMaxArgs()) { // If there are no optional arguments, then checking for the argument count // is trivial. - if (!checkAttributeNumArgs(S, Attr, Attr.getMinArgs())) + if (!checkAttributeNumArgs(S, AL, AL.getMinArgs())) return true; } else { // There are optional arguments, so checking is slightly more involved. - if (Attr.getMinArgs() && - !checkAttributeAtLeastNumArgs(S, Attr, Attr.getMinArgs())) + if (AL.getMinArgs() && + !checkAttributeAtLeastNumArgs(S, AL, AL.getMinArgs())) return true; - else if (!Attr.hasVariadicArg() && Attr.getMaxArgs() && - !checkAttributeAtMostNumArgs(S, Attr, Attr.getMaxArgs())) + else if (!AL.hasVariadicArg() && AL.getMaxArgs() && + !checkAttributeAtMostNumArgs(S, AL, AL.getMaxArgs())) return true; } + if (S.CheckAttrTarget(AL)) + return true; + return false; } -static void handleOpenCLAccessAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->isInvalidDecl()) return; // Check if there is only one access qualifier. if (D->hasAttr<OpenCLAccessAttr>()) { - S.Diag(Attr.getLoc(), diag::err_opencl_multiple_access_qualifiers) + S.Diag(AL.getLoc(), diag::err_opencl_multiple_access_qualifiers) << D->getSourceRange(); D->setInvalidDecl(true); return; @@ -5926,12 +5924,12 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, // 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. - if (const ParmVarDecl *PDecl = dyn_cast<ParmVarDecl>(D)) { + if (const auto *PDecl = dyn_cast<ParmVarDecl>(D)) { const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr(); - if (Attr.getName()->getName().find("read_write") != StringRef::npos) { + if (AL.getName()->getName().find("read_write") != StringRef::npos) { if (S.getLangOpts().OpenCLVersion < 200 || DeclTy->isPipeType()) { - S.Diag(Attr.getLoc(), diag::err_opencl_invalid_read_write) - << Attr.getName() << PDecl->getType() << DeclTy->isImageType(); + S.Diag(AL.getLoc(), diag::err_opencl_invalid_read_write) + << AL.getName() << PDecl->getType() << DeclTy->isImageType(); D->setInvalidDecl(true); return; } @@ -5939,7 +5937,7 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, } D->addAttr(::new (S.Context) OpenCLAccessAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } //===----------------------------------------------------------------------===// @@ -5950,633 +5948,662 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, /// the attribute applies to decls. If the attribute is a type attribute, just /// silently ignore it if a GNU attribute. static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, - const AttributeList &Attr, + const ParsedAttr &AL, bool IncludeCXX11Attributes) { - if (Attr.isInvalid() || Attr.getKind() == AttributeList::IgnoredAttribute) + if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute) return; // Ignore C++11 attributes on declarator chunks: they appertain to the type // instead. - if (Attr.isCXX11Attribute() && !IncludeCXX11Attributes) + if (AL.isCXX11Attribute() && !IncludeCXX11Attributes) return; // Unknown attributes are automatically warned on. Target-specific attributes // which do not apply to the current target architecture are treated as // though they were unknown attributes. - if (Attr.getKind() == AttributeList::UnknownAttribute || - !Attr.existsInTarget(S.Context.getTargetInfo())) { - S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute() - ? diag::warn_unhandled_ms_attribute_ignored - : diag::warn_unknown_attribute_ignored) - << Attr.getName(); + if (AL.getKind() == ParsedAttr::UnknownAttribute || + !AL.existsInTarget(S.Context.getTargetInfo())) { + S.Diag(AL.getLoc(), AL.isDeclspecAttribute() + ? diag::warn_unhandled_ms_attribute_ignored + : diag::warn_unknown_attribute_ignored) + << AL.getName(); return; } - if (handleCommonAttributeFeatures(S, scope, D, Attr)) + if (handleCommonAttributeFeatures(S, D, AL)) return; - switch (Attr.getKind()) { + switch (AL.getKind()) { default: - if (!Attr.isStmtAttr()) { + if (!AL.isStmtAttr()) { // Type attributes are handled elsewhere; silently move on. - assert(Attr.isTypeAttr() && "Non-type attribute not handled"); + assert(AL.isTypeAttr() && "Non-type attribute not handled"); break; } - S.Diag(Attr.getLoc(), diag::err_stmt_attribute_invalid_on_decl) - << Attr.getName() << D->getLocation(); + S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl) + << AL.getName() << D->getLocation(); break; - case AttributeList::AT_Interrupt: - handleInterruptAttr(S, D, Attr); + case ParsedAttr::AT_Interrupt: + handleInterruptAttr(S, D, AL); break; - case AttributeList::AT_X86ForceAlignArgPointer: - handleX86ForceAlignArgPointerAttr(S, D, Attr); + case ParsedAttr::AT_X86ForceAlignArgPointer: + handleX86ForceAlignArgPointerAttr(S, D, AL); break; - case AttributeList::AT_DLLExport: - case AttributeList::AT_DLLImport: - handleDLLAttr(S, D, Attr); + case ParsedAttr::AT_DLLExport: + case ParsedAttr::AT_DLLImport: + handleDLLAttr(S, D, AL); break; - case AttributeList::AT_Mips16: + case ParsedAttr::AT_Mips16: handleSimpleAttributeWithExclusions<Mips16Attr, MicroMipsAttr, - MipsInterruptAttr>(S, D, Attr); + MipsInterruptAttr>(S, D, AL); break; - case AttributeList::AT_NoMips16: - handleSimpleAttribute<NoMips16Attr>(S, D, Attr); + case ParsedAttr::AT_NoMips16: + handleSimpleAttribute<NoMips16Attr>(S, D, AL); break; - case AttributeList::AT_MicroMips: - handleSimpleAttributeWithExclusions<MicroMipsAttr, Mips16Attr>(S, D, Attr); + case ParsedAttr::AT_MicroMips: + handleSimpleAttributeWithExclusions<MicroMipsAttr, Mips16Attr>(S, D, AL); break; - case AttributeList::AT_NoMicroMips: - handleSimpleAttribute<NoMicroMipsAttr>(S, D, Attr); + case ParsedAttr::AT_NoMicroMips: + handleSimpleAttribute<NoMicroMipsAttr>(S, D, AL); break; - case AttributeList::AT_MipsLongCall: + case ParsedAttr::AT_MipsLongCall: handleSimpleAttributeWithExclusions<MipsLongCallAttr, MipsShortCallAttr>( - S, D, Attr); + S, D, AL); break; - case AttributeList::AT_MipsShortCall: + case ParsedAttr::AT_MipsShortCall: handleSimpleAttributeWithExclusions<MipsShortCallAttr, MipsLongCallAttr>( - S, D, Attr); + S, D, AL); + break; + case ParsedAttr::AT_AMDGPUFlatWorkGroupSize: + handleAMDGPUFlatWorkGroupSizeAttr(S, D, AL); + break; + case ParsedAttr::AT_AMDGPUWavesPerEU: + handleAMDGPUWavesPerEUAttr(S, D, AL); break; - case AttributeList::AT_AMDGPUFlatWorkGroupSize: - handleAMDGPUFlatWorkGroupSizeAttr(S, D, Attr); + case ParsedAttr::AT_AMDGPUNumSGPR: + handleAMDGPUNumSGPRAttr(S, D, AL); break; - case AttributeList::AT_AMDGPUWavesPerEU: - handleAMDGPUWavesPerEUAttr(S, D, Attr); + case ParsedAttr::AT_AMDGPUNumVGPR: + handleAMDGPUNumVGPRAttr(S, D, AL); break; - case AttributeList::AT_AMDGPUNumSGPR: - handleAMDGPUNumSGPRAttr(S, D, Attr); + case ParsedAttr::AT_AVRSignal: + handleAVRSignalAttr(S, D, AL); break; - case AttributeList::AT_AMDGPUNumVGPR: - handleAMDGPUNumVGPRAttr(S, D, Attr); + case ParsedAttr::AT_IBAction: + handleSimpleAttribute<IBActionAttr>(S, D, AL); break; - case AttributeList::AT_AVRSignal: - handleAVRSignalAttr(S, D, Attr); + case ParsedAttr::AT_IBOutlet: + handleIBOutlet(S, D, AL); break; - case AttributeList::AT_IBAction: - handleSimpleAttribute<IBActionAttr>(S, D, Attr); + case ParsedAttr::AT_IBOutletCollection: + handleIBOutletCollection(S, D, AL); break; - case AttributeList::AT_IBOutlet: - handleIBOutlet(S, D, Attr); + case ParsedAttr::AT_IFunc: + handleIFuncAttr(S, D, AL); break; - case AttributeList::AT_IBOutletCollection: - handleIBOutletCollection(S, D, Attr); + case ParsedAttr::AT_Alias: + handleAliasAttr(S, D, AL); break; - case AttributeList::AT_IFunc: - handleIFuncAttr(S, D, Attr); + case ParsedAttr::AT_Aligned: + handleAlignedAttr(S, D, AL); break; - case AttributeList::AT_Alias: - handleAliasAttr(S, D, Attr); + case ParsedAttr::AT_AlignValue: + handleAlignValueAttr(S, D, AL); break; - case AttributeList::AT_Aligned: - handleAlignedAttr(S, D, Attr); + case ParsedAttr::AT_AllocSize: + handleAllocSizeAttr(S, D, AL); break; - case AttributeList::AT_AlignValue: - handleAlignValueAttr(S, D, Attr); + case ParsedAttr::AT_AlwaysInline: + handleAlwaysInlineAttr(S, D, AL); break; - case AttributeList::AT_AllocSize: - handleAllocSizeAttr(S, D, Attr); + case ParsedAttr::AT_Artificial: + handleSimpleAttribute<ArtificialAttr>(S, D, AL); break; - case AttributeList::AT_AlwaysInline: - handleAlwaysInlineAttr(S, D, Attr); + case ParsedAttr::AT_AnalyzerNoReturn: + handleAnalyzerNoReturnAttr(S, D, AL); break; - case AttributeList::AT_AnalyzerNoReturn: - handleAnalyzerNoReturnAttr(S, D, Attr); + case ParsedAttr::AT_TLSModel: + handleTLSModelAttr(S, D, AL); break; - case AttributeList::AT_TLSModel: - handleTLSModelAttr(S, D, Attr); + case ParsedAttr::AT_Annotate: + handleAnnotateAttr(S, D, AL); break; - case AttributeList::AT_Annotate: - handleAnnotateAttr(S, D, Attr); + case ParsedAttr::AT_Availability: + handleAvailabilityAttr(S, D, AL); break; - case AttributeList::AT_Availability: - handleAvailabilityAttr(S, D, Attr); + case ParsedAttr::AT_CarriesDependency: + handleDependencyAttr(S, scope, D, AL); break; - case AttributeList::AT_CarriesDependency: - handleDependencyAttr(S, scope, D, Attr); + case ParsedAttr::AT_CPUDispatch: + case ParsedAttr::AT_CPUSpecific: + handleCPUSpecificAttr(S, D, AL); break; - case AttributeList::AT_Common: - handleCommonAttr(S, D, Attr); + case ParsedAttr::AT_Common: + handleCommonAttr(S, D, AL); break; - case AttributeList::AT_CUDAConstant: - handleConstantAttr(S, D, Attr); + case ParsedAttr::AT_CUDAConstant: + handleConstantAttr(S, D, AL); break; - case AttributeList::AT_PassObjectSize: - handlePassObjectSizeAttr(S, D, Attr); + case ParsedAttr::AT_PassObjectSize: + handlePassObjectSizeAttr(S, D, AL); break; - case AttributeList::AT_Constructor: - handleConstructorAttr(S, D, Attr); + case ParsedAttr::AT_Constructor: + handleConstructorAttr(S, D, AL); break; - case AttributeList::AT_CXX11NoReturn: - handleSimpleAttribute<CXX11NoReturnAttr>(S, D, Attr); + case ParsedAttr::AT_CXX11NoReturn: + handleSimpleAttribute<CXX11NoReturnAttr>(S, D, AL); break; - case AttributeList::AT_Deprecated: - handleDeprecatedAttr(S, D, Attr); + case ParsedAttr::AT_Deprecated: + handleDeprecatedAttr(S, D, AL); break; - case AttributeList::AT_Destructor: - handleDestructorAttr(S, D, Attr); + case ParsedAttr::AT_Destructor: + handleDestructorAttr(S, D, AL); break; - case AttributeList::AT_EnableIf: - handleEnableIfAttr(S, D, Attr); + case ParsedAttr::AT_EnableIf: + handleEnableIfAttr(S, D, AL); break; - case AttributeList::AT_DiagnoseIf: - handleDiagnoseIfAttr(S, D, Attr); + case ParsedAttr::AT_DiagnoseIf: + handleDiagnoseIfAttr(S, D, AL); break; - case AttributeList::AT_ExtVectorType: - handleExtVectorTypeAttr(S, scope, D, Attr); + case ParsedAttr::AT_ExtVectorType: + handleExtVectorTypeAttr(S, D, AL); break; - case AttributeList::AT_ExternalSourceSymbol: - handleExternalSourceSymbolAttr(S, D, Attr); + case ParsedAttr::AT_ExternalSourceSymbol: + handleExternalSourceSymbolAttr(S, D, AL); break; - case AttributeList::AT_MinSize: - handleMinSizeAttr(S, D, Attr); + case ParsedAttr::AT_MinSize: + handleMinSizeAttr(S, D, AL); break; - case AttributeList::AT_OptimizeNone: - handleOptimizeNoneAttr(S, D, Attr); + case ParsedAttr::AT_OptimizeNone: + handleOptimizeNoneAttr(S, D, AL); break; - case AttributeList::AT_FlagEnum: - handleSimpleAttribute<FlagEnumAttr>(S, D, Attr); + case ParsedAttr::AT_FlagEnum: + handleSimpleAttribute<FlagEnumAttr>(S, D, AL); break; - case AttributeList::AT_EnumExtensibility: - handleEnumExtensibilityAttr(S, D, Attr); + case ParsedAttr::AT_EnumExtensibility: + handleEnumExtensibilityAttr(S, D, AL); break; - case AttributeList::AT_Flatten: - handleSimpleAttribute<FlattenAttr>(S, D, Attr); + case ParsedAttr::AT_Flatten: + handleSimpleAttribute<FlattenAttr>(S, D, AL); break; - case AttributeList::AT_Format: - handleFormatAttr(S, D, Attr); + case ParsedAttr::AT_Format: + handleFormatAttr(S, D, AL); break; - case AttributeList::AT_FormatArg: - handleFormatArgAttr(S, D, Attr); + case ParsedAttr::AT_FormatArg: + handleFormatArgAttr(S, D, AL); break; - case AttributeList::AT_CUDAGlobal: - handleGlobalAttr(S, D, Attr); + case ParsedAttr::AT_CUDAGlobal: + handleGlobalAttr(S, D, AL); break; - case AttributeList::AT_CUDADevice: + case ParsedAttr::AT_CUDADevice: handleSimpleAttributeWithExclusions<CUDADeviceAttr, CUDAGlobalAttr>(S, D, - Attr); + AL); break; - case AttributeList::AT_CUDAHost: - handleSimpleAttributeWithExclusions<CUDAHostAttr, CUDAGlobalAttr>(S, D, - Attr); + case ParsedAttr::AT_CUDAHost: + handleSimpleAttributeWithExclusions<CUDAHostAttr, CUDAGlobalAttr>(S, D, AL); break; - case AttributeList::AT_GNUInline: - handleGNUInlineAttr(S, D, Attr); + case ParsedAttr::AT_GNUInline: + handleGNUInlineAttr(S, D, AL); break; - case AttributeList::AT_CUDALaunchBounds: - handleLaunchBoundsAttr(S, D, Attr); + case ParsedAttr::AT_CUDALaunchBounds: + handleLaunchBoundsAttr(S, D, AL); break; - case AttributeList::AT_Restrict: - handleRestrictAttr(S, D, Attr); + case ParsedAttr::AT_Restrict: + handleRestrictAttr(S, D, AL); break; - case AttributeList::AT_MayAlias: - handleSimpleAttribute<MayAliasAttr>(S, D, Attr); + case ParsedAttr::AT_LifetimeBound: + handleSimpleAttribute<LifetimeBoundAttr>(S, D, AL); break; - case AttributeList::AT_Mode: - handleModeAttr(S, D, Attr); + case ParsedAttr::AT_MayAlias: + handleSimpleAttribute<MayAliasAttr>(S, D, AL); break; - case AttributeList::AT_NoAlias: - handleSimpleAttribute<NoAliasAttr>(S, D, Attr); + case ParsedAttr::AT_Mode: + handleModeAttr(S, D, AL); break; - case AttributeList::AT_NoCommon: - handleSimpleAttribute<NoCommonAttr>(S, D, Attr); + case ParsedAttr::AT_NoAlias: + handleSimpleAttribute<NoAliasAttr>(S, D, AL); break; - case AttributeList::AT_NoSplitStack: - handleSimpleAttribute<NoSplitStackAttr>(S, D, Attr); + case ParsedAttr::AT_NoCommon: + handleSimpleAttribute<NoCommonAttr>(S, D, AL); break; - case AttributeList::AT_NonNull: - if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(D)) - handleNonNullAttrParameter(S, PVD, Attr); + case ParsedAttr::AT_NoSplitStack: + handleSimpleAttribute<NoSplitStackAttr>(S, D, AL); + break; + case ParsedAttr::AT_NonNull: + if (auto *PVD = dyn_cast<ParmVarDecl>(D)) + handleNonNullAttrParameter(S, PVD, AL); else - handleNonNullAttr(S, D, Attr); + handleNonNullAttr(S, D, AL); + break; + case ParsedAttr::AT_ReturnsNonNull: + handleReturnsNonNullAttr(S, D, AL); + break; + case ParsedAttr::AT_NoEscape: + handleNoEscapeAttr(S, D, AL); + break; + case ParsedAttr::AT_AssumeAligned: + handleAssumeAlignedAttr(S, D, AL); + break; + case ParsedAttr::AT_AllocAlign: + handleAllocAlignAttr(S, D, AL); break; - case AttributeList::AT_ReturnsNonNull: - handleReturnsNonNullAttr(S, D, Attr); + case ParsedAttr::AT_Overloadable: + handleSimpleAttribute<OverloadableAttr>(S, D, AL); break; - case AttributeList::AT_NoEscape: - handleNoEscapeAttr(S, D, Attr); + case ParsedAttr::AT_Ownership: + handleOwnershipAttr(S, D, AL); break; - case AttributeList::AT_AssumeAligned: - handleAssumeAlignedAttr(S, D, Attr); + case ParsedAttr::AT_Cold: + handleSimpleAttributeWithExclusions<ColdAttr, HotAttr>(S, D, AL); break; - case AttributeList::AT_AllocAlign: - handleAllocAlignAttr(S, D, Attr); + case ParsedAttr::AT_Hot: + handleSimpleAttributeWithExclusions<HotAttr, ColdAttr>(S, D, AL); break; - case AttributeList::AT_Overloadable: - handleSimpleAttribute<OverloadableAttr>(S, D, Attr); + case ParsedAttr::AT_Naked: + handleNakedAttr(S, D, AL); break; - case AttributeList::AT_Ownership: - handleOwnershipAttr(S, D, Attr); + case ParsedAttr::AT_NoReturn: + handleNoReturnAttr(S, D, AL); break; - case AttributeList::AT_Cold: - handleColdAttr(S, D, Attr); + case ParsedAttr::AT_AnyX86NoCfCheck: + handleNoCfCheckAttr(S, D, AL); break; - case AttributeList::AT_Hot: - handleHotAttr(S, D, Attr); + case ParsedAttr::AT_NoThrow: + handleSimpleAttribute<NoThrowAttr>(S, D, AL); break; - case AttributeList::AT_Naked: - handleNakedAttr(S, D, Attr); + case ParsedAttr::AT_CUDAShared: + handleSharedAttr(S, D, AL); break; - case AttributeList::AT_NoReturn: - handleNoReturnAttr(S, D, Attr); + case ParsedAttr::AT_VecReturn: + handleVecReturnAttr(S, D, AL); break; - case AttributeList::AT_NoThrow: - handleSimpleAttribute<NoThrowAttr>(S, D, Attr); + case ParsedAttr::AT_ObjCOwnership: + handleObjCOwnershipAttr(S, D, AL); break; - case AttributeList::AT_CUDAShared: - handleSharedAttr(S, D, Attr); + case ParsedAttr::AT_ObjCPreciseLifetime: + handleObjCPreciseLifetimeAttr(S, D, AL); break; - case AttributeList::AT_VecReturn: - handleVecReturnAttr(S, D, Attr); + case ParsedAttr::AT_ObjCReturnsInnerPointer: + handleObjCReturnsInnerPointerAttr(S, D, AL); break; - case AttributeList::AT_ObjCOwnership: - handleObjCOwnershipAttr(S, D, Attr); + case ParsedAttr::AT_ObjCRequiresSuper: + handleObjCRequiresSuperAttr(S, D, AL); break; - case AttributeList::AT_ObjCPreciseLifetime: - handleObjCPreciseLifetimeAttr(S, D, Attr); + case ParsedAttr::AT_ObjCBridge: + handleObjCBridgeAttr(S, D, AL); break; - case AttributeList::AT_ObjCReturnsInnerPointer: - handleObjCReturnsInnerPointerAttr(S, D, Attr); + case ParsedAttr::AT_ObjCBridgeMutable: + handleObjCBridgeMutableAttr(S, D, AL); break; - case AttributeList::AT_ObjCRequiresSuper: - handleObjCRequiresSuperAttr(S, D, Attr); + case ParsedAttr::AT_ObjCBridgeRelated: + handleObjCBridgeRelatedAttr(S, D, AL); break; - case AttributeList::AT_ObjCBridge: - handleObjCBridgeAttr(S, scope, D, Attr); + case ParsedAttr::AT_ObjCDesignatedInitializer: + handleObjCDesignatedInitializer(S, D, AL); break; - case AttributeList::AT_ObjCBridgeMutable: - handleObjCBridgeMutableAttr(S, scope, D, Attr); + case ParsedAttr::AT_ObjCRuntimeName: + handleObjCRuntimeName(S, D, AL); break; - case AttributeList::AT_ObjCBridgeRelated: - handleObjCBridgeRelatedAttr(S, scope, D, Attr); + case ParsedAttr::AT_ObjCRuntimeVisible: + handleSimpleAttribute<ObjCRuntimeVisibleAttr>(S, D, AL); break; - case AttributeList::AT_ObjCDesignatedInitializer: - handleObjCDesignatedInitializer(S, D, Attr); + case ParsedAttr::AT_ObjCBoxable: + handleObjCBoxable(S, D, AL); break; - case AttributeList::AT_ObjCRuntimeName: - handleObjCRuntimeName(S, D, Attr); + case ParsedAttr::AT_CFAuditedTransfer: + handleSimpleAttributeWithExclusions<CFAuditedTransferAttr, + CFUnknownTransferAttr>(S, D, AL); break; - case AttributeList::AT_ObjCRuntimeVisible: - handleSimpleAttribute<ObjCRuntimeVisibleAttr>(S, D, Attr); + case ParsedAttr::AT_CFUnknownTransfer: + handleSimpleAttributeWithExclusions<CFUnknownTransferAttr, + CFAuditedTransferAttr>(S, D, AL); break; - case AttributeList::AT_ObjCBoxable: - handleObjCBoxable(S, D, Attr); + case ParsedAttr::AT_CFConsumed: + case ParsedAttr::AT_NSConsumed: + handleNSConsumedAttr(S, D, AL); break; - case AttributeList::AT_CFAuditedTransfer: - handleCFAuditedTransferAttr(S, D, Attr); + case ParsedAttr::AT_NSConsumesSelf: + handleSimpleAttribute<NSConsumesSelfAttr>(S, D, AL); break; - case AttributeList::AT_CFUnknownTransfer: - handleCFUnknownTransferAttr(S, D, Attr); + case ParsedAttr::AT_NSReturnsAutoreleased: + case ParsedAttr::AT_NSReturnsNotRetained: + case ParsedAttr::AT_CFReturnsNotRetained: + case ParsedAttr::AT_NSReturnsRetained: + case ParsedAttr::AT_CFReturnsRetained: + handleNSReturnsRetainedAttr(S, D, AL); break; - case AttributeList::AT_CFConsumed: - case AttributeList::AT_NSConsumed: - handleNSConsumedAttr(S, D, Attr); + case ParsedAttr::AT_WorkGroupSizeHint: + handleWorkGroupSize<WorkGroupSizeHintAttr>(S, D, AL); break; - case AttributeList::AT_NSConsumesSelf: - handleSimpleAttribute<NSConsumesSelfAttr>(S, D, Attr); + case ParsedAttr::AT_ReqdWorkGroupSize: + handleWorkGroupSize<ReqdWorkGroupSizeAttr>(S, D, AL); break; - case AttributeList::AT_NSReturnsAutoreleased: - case AttributeList::AT_NSReturnsNotRetained: - case AttributeList::AT_CFReturnsNotRetained: - case AttributeList::AT_NSReturnsRetained: - case AttributeList::AT_CFReturnsRetained: - handleNSReturnsRetainedAttr(S, D, Attr); + case ParsedAttr::AT_OpenCLIntelReqdSubGroupSize: + handleSubGroupSize(S, D, AL); break; - case AttributeList::AT_WorkGroupSizeHint: - handleWorkGroupSize<WorkGroupSizeHintAttr>(S, D, Attr); + case ParsedAttr::AT_VecTypeHint: + handleVecTypeHint(S, D, AL); break; - case AttributeList::AT_ReqdWorkGroupSize: - handleWorkGroupSize<ReqdWorkGroupSizeAttr>(S, D, Attr); + case ParsedAttr::AT_RequireConstantInit: + handleSimpleAttribute<RequireConstantInitAttr>(S, D, AL); break; - case AttributeList::AT_OpenCLIntelReqdSubGroupSize: - handleSubGroupSize(S, D, Attr); + case ParsedAttr::AT_InitPriority: + handleInitPriorityAttr(S, D, AL); break; - case AttributeList::AT_VecTypeHint: - handleVecTypeHint(S, D, Attr); + case ParsedAttr::AT_Packed: + handlePackedAttr(S, D, AL); break; - case AttributeList::AT_RequireConstantInit: - handleSimpleAttribute<RequireConstantInitAttr>(S, D, Attr); + case ParsedAttr::AT_Section: + handleSectionAttr(S, D, AL); break; - case AttributeList::AT_InitPriority: - handleInitPriorityAttr(S, D, Attr); + case ParsedAttr::AT_CodeSeg: + handleCodeSegAttr(S, D, AL); break; - case AttributeList::AT_Packed: - handlePackedAttr(S, D, Attr); + case ParsedAttr::AT_Target: + handleTargetAttr(S, D, AL); break; - case AttributeList::AT_Section: - handleSectionAttr(S, D, Attr); + case ParsedAttr::AT_MinVectorWidth: + handleMinVectorWidthAttr(S, D, AL); break; - case AttributeList::AT_Target: - handleTargetAttr(S, D, Attr); + case ParsedAttr::AT_Unavailable: + handleAttrWithMessage<UnavailableAttr>(S, D, AL); break; - case AttributeList::AT_Unavailable: - handleAttrWithMessage<UnavailableAttr>(S, D, Attr); + case ParsedAttr::AT_ArcWeakrefUnavailable: + handleSimpleAttribute<ArcWeakrefUnavailableAttr>(S, D, AL); break; - case AttributeList::AT_ArcWeakrefUnavailable: - handleSimpleAttribute<ArcWeakrefUnavailableAttr>(S, D, Attr); + case ParsedAttr::AT_ObjCRootClass: + handleSimpleAttribute<ObjCRootClassAttr>(S, D, AL); break; - case AttributeList::AT_ObjCRootClass: - handleSimpleAttribute<ObjCRootClassAttr>(S, D, Attr); + case ParsedAttr::AT_ObjCSubclassingRestricted: + handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, AL); break; - case AttributeList::AT_ObjCSubclassingRestricted: - handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, Attr); + case ParsedAttr::AT_ObjCExplicitProtocolImpl: + handleObjCSuppresProtocolAttr(S, D, AL); break; - case AttributeList::AT_ObjCExplicitProtocolImpl: - handleObjCSuppresProtocolAttr(S, D, Attr); + case ParsedAttr::AT_ObjCRequiresPropertyDefs: + handleSimpleAttribute<ObjCRequiresPropertyDefsAttr>(S, D, AL); break; - case AttributeList::AT_ObjCRequiresPropertyDefs: - handleSimpleAttribute<ObjCRequiresPropertyDefsAttr>(S, D, Attr); + case ParsedAttr::AT_Unused: + handleUnusedAttr(S, D, AL); break; - case AttributeList::AT_Unused: - handleUnusedAttr(S, D, Attr); + case ParsedAttr::AT_ReturnsTwice: + handleSimpleAttribute<ReturnsTwiceAttr>(S, D, AL); break; - case AttributeList::AT_ReturnsTwice: - handleSimpleAttribute<ReturnsTwiceAttr>(S, D, Attr); + case ParsedAttr::AT_NotTailCalled: + handleSimpleAttributeWithExclusions<NotTailCalledAttr, AlwaysInlineAttr>( + S, D, AL); break; - case AttributeList::AT_NotTailCalled: - handleNotTailCalledAttr(S, D, Attr); + case ParsedAttr::AT_DisableTailCalls: + handleSimpleAttributeWithExclusions<DisableTailCallsAttr, NakedAttr>(S, D, + AL); break; - case AttributeList::AT_DisableTailCalls: - handleDisableTailCallsAttr(S, D, Attr); + case ParsedAttr::AT_Used: + handleSimpleAttribute<UsedAttr>(S, D, AL); break; - case AttributeList::AT_Used: - handleUsedAttr(S, D, Attr); + case ParsedAttr::AT_Visibility: + handleVisibilityAttr(S, D, AL, false); break; - case AttributeList::AT_Visibility: - handleVisibilityAttr(S, D, Attr, false); + case ParsedAttr::AT_TypeVisibility: + handleVisibilityAttr(S, D, AL, true); break; - case AttributeList::AT_TypeVisibility: - handleVisibilityAttr(S, D, Attr, true); + case ParsedAttr::AT_WarnUnused: + handleSimpleAttribute<WarnUnusedAttr>(S, D, AL); break; - case AttributeList::AT_WarnUnused: - handleSimpleAttribute<WarnUnusedAttr>(S, D, Attr); + case ParsedAttr::AT_WarnUnusedResult: + handleWarnUnusedResult(S, D, AL); break; - case AttributeList::AT_WarnUnusedResult: - handleWarnUnusedResult(S, D, Attr); + case ParsedAttr::AT_Weak: + handleSimpleAttribute<WeakAttr>(S, D, AL); break; - case AttributeList::AT_Weak: - handleSimpleAttribute<WeakAttr>(S, D, Attr); + case ParsedAttr::AT_WeakRef: + handleWeakRefAttr(S, D, AL); break; - case AttributeList::AT_WeakRef: - handleWeakRefAttr(S, D, Attr); + case ParsedAttr::AT_WeakImport: + handleWeakImportAttr(S, D, AL); break; - case AttributeList::AT_WeakImport: - handleWeakImportAttr(S, D, Attr); + case ParsedAttr::AT_TransparentUnion: + handleTransparentUnionAttr(S, D, AL); break; - case AttributeList::AT_TransparentUnion: - handleTransparentUnionAttr(S, D, Attr); + case ParsedAttr::AT_ObjCException: + handleSimpleAttribute<ObjCExceptionAttr>(S, D, AL); break; - case AttributeList::AT_ObjCException: - handleSimpleAttribute<ObjCExceptionAttr>(S, D, Attr); + case ParsedAttr::AT_ObjCMethodFamily: + handleObjCMethodFamilyAttr(S, D, AL); break; - case AttributeList::AT_ObjCMethodFamily: - handleObjCMethodFamilyAttr(S, D, Attr); + case ParsedAttr::AT_ObjCNSObject: + handleObjCNSObject(S, D, AL); break; - case AttributeList::AT_ObjCNSObject: - handleObjCNSObject(S, D, Attr); + case ParsedAttr::AT_ObjCIndependentClass: + handleObjCIndependentClass(S, D, AL); break; - case AttributeList::AT_ObjCIndependentClass: - handleObjCIndependentClass(S, D, Attr); + case ParsedAttr::AT_Blocks: + handleBlocksAttr(S, D, AL); break; - case AttributeList::AT_Blocks: - handleBlocksAttr(S, D, Attr); + case ParsedAttr::AT_Sentinel: + handleSentinelAttr(S, D, AL); break; - case AttributeList::AT_Sentinel: - handleSentinelAttr(S, D, Attr); + case ParsedAttr::AT_Const: + handleSimpleAttribute<ConstAttr>(S, D, AL); break; - case AttributeList::AT_Const: - handleSimpleAttribute<ConstAttr>(S, D, Attr); + case ParsedAttr::AT_Pure: + handleSimpleAttribute<PureAttr>(S, D, AL); break; - case AttributeList::AT_Pure: - handleSimpleAttribute<PureAttr>(S, D, Attr); + case ParsedAttr::AT_Cleanup: + handleCleanupAttr(S, D, AL); break; - case AttributeList::AT_Cleanup: - handleCleanupAttr(S, D, Attr); + case ParsedAttr::AT_NoDebug: + handleNoDebugAttr(S, D, AL); break; - case AttributeList::AT_NoDebug: - handleNoDebugAttr(S, D, Attr); + case ParsedAttr::AT_NoDuplicate: + handleSimpleAttribute<NoDuplicateAttr>(S, D, AL); break; - case AttributeList::AT_NoDuplicate: - handleSimpleAttribute<NoDuplicateAttr>(S, D, Attr); + case ParsedAttr::AT_Convergent: + handleSimpleAttribute<ConvergentAttr>(S, D, AL); break; - case AttributeList::AT_Convergent: - handleSimpleAttribute<ConvergentAttr>(S, D, Attr); + case ParsedAttr::AT_NoInline: + handleSimpleAttribute<NoInlineAttr>(S, D, AL); break; - case AttributeList::AT_NoInline: - handleSimpleAttribute<NoInlineAttr>(S, D, Attr); + case ParsedAttr::AT_NoInstrumentFunction: // Interacts with -pg. + handleSimpleAttribute<NoInstrumentFunctionAttr>(S, D, AL); break; - case AttributeList::AT_NoInstrumentFunction: // Interacts with -pg. - handleSimpleAttribute<NoInstrumentFunctionAttr>(S, D, Attr); + case ParsedAttr::AT_NoStackProtector: + // Interacts with -fstack-protector options. + handleSimpleAttribute<NoStackProtectorAttr>(S, D, AL); break; - case AttributeList::AT_StdCall: - case AttributeList::AT_CDecl: - case AttributeList::AT_FastCall: - case AttributeList::AT_ThisCall: - case AttributeList::AT_Pascal: - case AttributeList::AT_RegCall: - case AttributeList::AT_SwiftCall: - case AttributeList::AT_VectorCall: - case AttributeList::AT_MSABI: - case AttributeList::AT_SysVABI: - case AttributeList::AT_Pcs: - case AttributeList::AT_IntelOclBicc: - case AttributeList::AT_PreserveMost: - case AttributeList::AT_PreserveAll: - handleCallConvAttr(S, D, Attr); + case ParsedAttr::AT_StdCall: + case ParsedAttr::AT_CDecl: + case ParsedAttr::AT_FastCall: + case ParsedAttr::AT_ThisCall: + case ParsedAttr::AT_Pascal: + case ParsedAttr::AT_RegCall: + case ParsedAttr::AT_SwiftCall: + case ParsedAttr::AT_VectorCall: + case ParsedAttr::AT_MSABI: + case ParsedAttr::AT_SysVABI: + case ParsedAttr::AT_Pcs: + case ParsedAttr::AT_IntelOclBicc: + case ParsedAttr::AT_PreserveMost: + case ParsedAttr::AT_PreserveAll: + handleCallConvAttr(S, D, AL); break; - case AttributeList::AT_Suppress: - handleSuppressAttr(S, D, Attr); + case ParsedAttr::AT_Suppress: + handleSuppressAttr(S, D, AL); break; - case AttributeList::AT_OpenCLKernel: - handleSimpleAttribute<OpenCLKernelAttr>(S, D, Attr); + case ParsedAttr::AT_OpenCLKernel: + handleSimpleAttribute<OpenCLKernelAttr>(S, D, AL); break; - case AttributeList::AT_OpenCLAccess: - handleOpenCLAccessAttr(S, D, Attr); + case ParsedAttr::AT_OpenCLAccess: + handleOpenCLAccessAttr(S, D, AL); break; - case AttributeList::AT_OpenCLNoSVM: - handleOpenCLNoSVMAttr(S, D, Attr); + case ParsedAttr::AT_OpenCLNoSVM: + handleOpenCLNoSVMAttr(S, D, AL); break; - case AttributeList::AT_SwiftContext: - handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftContext); + case ParsedAttr::AT_SwiftContext: + handleParameterABIAttr(S, D, AL, ParameterABI::SwiftContext); break; - case AttributeList::AT_SwiftErrorResult: - handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftErrorResult); + case ParsedAttr::AT_SwiftErrorResult: + handleParameterABIAttr(S, D, AL, ParameterABI::SwiftErrorResult); break; - case AttributeList::AT_SwiftIndirectResult: - handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftIndirectResult); + case ParsedAttr::AT_SwiftIndirectResult: + handleParameterABIAttr(S, D, AL, ParameterABI::SwiftIndirectResult); break; - case AttributeList::AT_InternalLinkage: - handleInternalLinkageAttr(S, D, Attr); + case ParsedAttr::AT_InternalLinkage: + handleInternalLinkageAttr(S, D, AL); break; - case AttributeList::AT_LTOVisibilityPublic: - handleSimpleAttribute<LTOVisibilityPublicAttr>(S, D, Attr); + case ParsedAttr::AT_LTOVisibilityPublic: + handleSimpleAttribute<LTOVisibilityPublicAttr>(S, D, AL); break; // Microsoft attributes: - case AttributeList::AT_EmptyBases: - handleSimpleAttribute<EmptyBasesAttr>(S, D, Attr); + case ParsedAttr::AT_EmptyBases: + handleSimpleAttribute<EmptyBasesAttr>(S, D, AL); break; - case AttributeList::AT_LayoutVersion: - handleLayoutVersion(S, D, Attr); + case ParsedAttr::AT_LayoutVersion: + handleLayoutVersion(S, D, AL); break; - case AttributeList::AT_MSNoVTable: - handleSimpleAttribute<MSNoVTableAttr>(S, D, Attr); + case ParsedAttr::AT_TrivialABI: + handleSimpleAttribute<TrivialABIAttr>(S, D, AL); break; - case AttributeList::AT_MSStruct: - handleSimpleAttribute<MSStructAttr>(S, D, Attr); + case ParsedAttr::AT_MSNoVTable: + handleSimpleAttribute<MSNoVTableAttr>(S, D, AL); break; - case AttributeList::AT_Uuid: - handleUuidAttr(S, D, Attr); + case ParsedAttr::AT_MSStruct: + handleSimpleAttribute<MSStructAttr>(S, D, AL); break; - case AttributeList::AT_MSInheritance: - handleMSInheritanceAttr(S, D, Attr); + case ParsedAttr::AT_Uuid: + handleUuidAttr(S, D, AL); break; - case AttributeList::AT_SelectAny: - handleSimpleAttribute<SelectAnyAttr>(S, D, Attr); + case ParsedAttr::AT_MSInheritance: + handleMSInheritanceAttr(S, D, AL); break; - case AttributeList::AT_Thread: - handleDeclspecThreadAttr(S, D, Attr); + case ParsedAttr::AT_SelectAny: + handleSimpleAttribute<SelectAnyAttr>(S, D, AL); + break; + case ParsedAttr::AT_Thread: + handleDeclspecThreadAttr(S, D, AL); break; - case AttributeList::AT_AbiTag: - handleAbiTagAttr(S, D, Attr); + case ParsedAttr::AT_AbiTag: + handleAbiTagAttr(S, D, AL); break; // Thread safety attributes: - case AttributeList::AT_AssertExclusiveLock: - handleAssertExclusiveLockAttr(S, D, Attr); + case ParsedAttr::AT_AssertExclusiveLock: + handleAssertExclusiveLockAttr(S, D, AL); break; - case AttributeList::AT_AssertSharedLock: - handleAssertSharedLockAttr(S, D, Attr); + case ParsedAttr::AT_AssertSharedLock: + handleAssertSharedLockAttr(S, D, AL); break; - case AttributeList::AT_GuardedVar: - handleSimpleAttribute<GuardedVarAttr>(S, D, Attr); + case ParsedAttr::AT_GuardedVar: + handleSimpleAttribute<GuardedVarAttr>(S, D, AL); break; - case AttributeList::AT_PtGuardedVar: - handlePtGuardedVarAttr(S, D, Attr); + case ParsedAttr::AT_PtGuardedVar: + handlePtGuardedVarAttr(S, D, AL); break; - case AttributeList::AT_ScopedLockable: - handleSimpleAttribute<ScopedLockableAttr>(S, D, Attr); + case ParsedAttr::AT_ScopedLockable: + handleSimpleAttribute<ScopedLockableAttr>(S, D, AL); break; - case AttributeList::AT_NoSanitize: - handleNoSanitizeAttr(S, D, Attr); + case ParsedAttr::AT_NoSanitize: + handleNoSanitizeAttr(S, D, AL); break; - case AttributeList::AT_NoSanitizeSpecific: - handleNoSanitizeSpecificAttr(S, D, Attr); + case ParsedAttr::AT_NoSanitizeSpecific: + handleNoSanitizeSpecificAttr(S, D, AL); break; - case AttributeList::AT_NoThreadSafetyAnalysis: - handleSimpleAttribute<NoThreadSafetyAnalysisAttr>(S, D, Attr); + case ParsedAttr::AT_NoThreadSafetyAnalysis: + handleSimpleAttribute<NoThreadSafetyAnalysisAttr>(S, D, AL); break; - case AttributeList::AT_GuardedBy: - handleGuardedByAttr(S, D, Attr); + case ParsedAttr::AT_GuardedBy: + handleGuardedByAttr(S, D, AL); break; - case AttributeList::AT_PtGuardedBy: - handlePtGuardedByAttr(S, D, Attr); + case ParsedAttr::AT_PtGuardedBy: + handlePtGuardedByAttr(S, D, AL); break; - case AttributeList::AT_ExclusiveTrylockFunction: - handleExclusiveTrylockFunctionAttr(S, D, Attr); + case ParsedAttr::AT_ExclusiveTrylockFunction: + handleExclusiveTrylockFunctionAttr(S, D, AL); break; - case AttributeList::AT_LockReturned: - handleLockReturnedAttr(S, D, Attr); + case ParsedAttr::AT_LockReturned: + handleLockReturnedAttr(S, D, AL); break; - case AttributeList::AT_LocksExcluded: - handleLocksExcludedAttr(S, D, Attr); + case ParsedAttr::AT_LocksExcluded: + handleLocksExcludedAttr(S, D, AL); break; - case AttributeList::AT_SharedTrylockFunction: - handleSharedTrylockFunctionAttr(S, D, Attr); + case ParsedAttr::AT_SharedTrylockFunction: + handleSharedTrylockFunctionAttr(S, D, AL); break; - case AttributeList::AT_AcquiredBefore: - handleAcquiredBeforeAttr(S, D, Attr); + case ParsedAttr::AT_AcquiredBefore: + handleAcquiredBeforeAttr(S, D, AL); break; - case AttributeList::AT_AcquiredAfter: - handleAcquiredAfterAttr(S, D, Attr); + case ParsedAttr::AT_AcquiredAfter: + handleAcquiredAfterAttr(S, D, AL); break; // Capability analysis attributes. - case AttributeList::AT_Capability: - case AttributeList::AT_Lockable: - handleCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_Capability: + case ParsedAttr::AT_Lockable: + handleCapabilityAttr(S, D, AL); break; - case AttributeList::AT_RequiresCapability: - handleRequiresCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_RequiresCapability: + handleRequiresCapabilityAttr(S, D, AL); break; - case AttributeList::AT_AssertCapability: - handleAssertCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_AssertCapability: + handleAssertCapabilityAttr(S, D, AL); break; - case AttributeList::AT_AcquireCapability: - handleAcquireCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_AcquireCapability: + handleAcquireCapabilityAttr(S, D, AL); break; - case AttributeList::AT_ReleaseCapability: - handleReleaseCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_ReleaseCapability: + handleReleaseCapabilityAttr(S, D, AL); break; - case AttributeList::AT_TryAcquireCapability: - handleTryAcquireCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_TryAcquireCapability: + handleTryAcquireCapabilityAttr(S, D, AL); break; // Consumed analysis attributes. - case AttributeList::AT_Consumable: - handleConsumableAttr(S, D, Attr); + case ParsedAttr::AT_Consumable: + handleConsumableAttr(S, D, AL); break; - case AttributeList::AT_ConsumableAutoCast: - handleSimpleAttribute<ConsumableAutoCastAttr>(S, D, Attr); + case ParsedAttr::AT_ConsumableAutoCast: + handleSimpleAttribute<ConsumableAutoCastAttr>(S, D, AL); break; - case AttributeList::AT_ConsumableSetOnRead: - handleSimpleAttribute<ConsumableSetOnReadAttr>(S, D, Attr); + case ParsedAttr::AT_ConsumableSetOnRead: + handleSimpleAttribute<ConsumableSetOnReadAttr>(S, D, AL); break; - case AttributeList::AT_CallableWhen: - handleCallableWhenAttr(S, D, Attr); + case ParsedAttr::AT_CallableWhen: + handleCallableWhenAttr(S, D, AL); break; - case AttributeList::AT_ParamTypestate: - handleParamTypestateAttr(S, D, Attr); + case ParsedAttr::AT_ParamTypestate: + handleParamTypestateAttr(S, D, AL); break; - case AttributeList::AT_ReturnTypestate: - handleReturnTypestateAttr(S, D, Attr); + case ParsedAttr::AT_ReturnTypestate: + handleReturnTypestateAttr(S, D, AL); break; - case AttributeList::AT_SetTypestate: - handleSetTypestateAttr(S, D, Attr); + case ParsedAttr::AT_SetTypestate: + handleSetTypestateAttr(S, D, AL); break; - case AttributeList::AT_TestTypestate: - handleTestTypestateAttr(S, D, Attr); + case ParsedAttr::AT_TestTypestate: + handleTestTypestateAttr(S, D, AL); break; // Type safety attributes. - case AttributeList::AT_ArgumentWithTypeTag: - handleArgumentWithTypeTagAttr(S, D, Attr); + case ParsedAttr::AT_ArgumentWithTypeTag: + handleArgumentWithTypeTagAttr(S, D, AL); break; - case AttributeList::AT_TypeTagForDatatype: - handleTypeTagForDatatypeAttr(S, D, Attr); + case ParsedAttr::AT_TypeTagForDatatype: + handleTypeTagForDatatypeAttr(S, D, AL); break; - case AttributeList::AT_AnyX86NoCallerSavedRegisters: - handleNoCallerSavedRegsAttr(S, D, Attr); + case ParsedAttr::AT_AnyX86NoCallerSavedRegisters: + handleSimpleAttribute<AnyX86NoCallerSavedRegistersAttr>(S, D, AL); break; - case AttributeList::AT_RenderScriptKernel: - handleSimpleAttribute<RenderScriptKernelAttr>(S, D, Attr); + case ParsedAttr::AT_RenderScriptKernel: + handleSimpleAttribute<RenderScriptKernelAttr>(S, D, AL); break; // XRay attributes. - case AttributeList::AT_XRayInstrument: - handleSimpleAttribute<XRayInstrumentAttr>(S, D, Attr); + case ParsedAttr::AT_XRayInstrument: + handleSimpleAttribute<XRayInstrumentAttr>(S, D, AL); break; - case AttributeList::AT_XRayLogArgs: - handleXRayLogArgsAttr(S, D, Attr); + case ParsedAttr::AT_XRayLogArgs: + handleXRayLogArgsAttr(S, D, AL); break; } } @@ -6584,18 +6611,21 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, /// ProcessDeclAttributeList - Apply all the decl attributes in the specified /// attribute list to the specified decl, ignoring any type attributes. void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, - const AttributeList *AttrList, + const ParsedAttributesView &AttrList, bool IncludeCXX11Attributes) { - for (const AttributeList* l = AttrList; l; l = l->getNext()) - ProcessDeclAttribute(*this, S, D, *l, IncludeCXX11Attributes); + if (AttrList.empty()) + return; + + for (const ParsedAttr &AL : AttrList) + ProcessDeclAttribute(*this, S, D, AL, IncludeCXX11Attributes); // FIXME: We should be able to handle these cases in TableGen. // GCC accepts // static int a9 __attribute__((weakref)); // but that looks really pointless. We reject it. if (D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) { - Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias) - << cast<NamedDecl>(D); + Diag(AttrList.begin()->getLoc(), diag::err_attribute_weakref_without_alias) + << cast<NamedDecl>(D); D->dropAttr<WeakRefAttr>(); return; } @@ -6606,79 +6636,83 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, // attribute must never appear as a group" for attributes like cold and hot. if (!D->hasAttr<OpenCLKernelAttr>()) { // These attributes cannot be applied to a non-kernel function. - if (Attr *A = D->getAttr<ReqdWorkGroupSizeAttr>()) { + if (const auto *A = D->getAttr<ReqdWorkGroupSizeAttr>()) { // FIXME: This emits a different error message than // diag::err_attribute_wrong_decl_type + ExpectedKernelFunction. Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<WorkGroupSizeHintAttr>()) { + } else if (const auto *A = D->getAttr<WorkGroupSizeHintAttr>()) { Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<VecTypeHintAttr>()) { + } else if (const auto *A = D->getAttr<VecTypeHintAttr>()) { Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<AMDGPUFlatWorkGroupSizeAttr>()) { - Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; - D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<AMDGPUWavesPerEUAttr>()) { - Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; - D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<AMDGPUNumSGPRAttr>()) { - Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; - D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<AMDGPUNumVGPRAttr>()) { - Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; - D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>()) { + } else if (const auto *A = D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>()) { Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); + } else if (!D->hasAttr<CUDAGlobalAttr>()) { + if (const auto *A = D->getAttr<AMDGPUFlatWorkGroupSizeAttr>()) { + Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << A << ExpectedKernelFunction; + D->setInvalidDecl(); + } else if (const auto *A = D->getAttr<AMDGPUWavesPerEUAttr>()) { + Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << A << ExpectedKernelFunction; + D->setInvalidDecl(); + } else if (const auto *A = D->getAttr<AMDGPUNumSGPRAttr>()) { + Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << A << ExpectedKernelFunction; + D->setInvalidDecl(); + } else if (const auto *A = D->getAttr<AMDGPUNumVGPRAttr>()) { + Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << A << ExpectedKernelFunction; + D->setInvalidDecl(); + } } } } // Helper for delayed processing TransparentUnion attribute. -void Sema::ProcessDeclAttributeDelayed(Decl *D, const AttributeList *AttrList) { - for (const AttributeList *Attr = AttrList; Attr; Attr = Attr->getNext()) - if (Attr->getKind() == AttributeList::AT_TransparentUnion) { - handleTransparentUnionAttr(*this, D, *Attr); +void Sema::ProcessDeclAttributeDelayed(Decl *D, + const ParsedAttributesView &AttrList) { + for (const ParsedAttr &AL : AttrList) + if (AL.getKind() == ParsedAttr::AT_TransparentUnion) { + handleTransparentUnionAttr(*this, D, AL); break; } } // Annotation attributes are the only attributes allowed after an access // specifier. -bool Sema::ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, - const AttributeList *AttrList) { - for (const AttributeList* l = AttrList; l; l = l->getNext()) { - if (l->getKind() == AttributeList::AT_Annotate) { - ProcessDeclAttribute(*this, nullptr, ASDecl, *l, l->isCXX11Attribute()); +bool Sema::ProcessAccessDeclAttributeList( + AccessSpecDecl *ASDecl, const ParsedAttributesView &AttrList) { + for (const ParsedAttr &AL : AttrList) { + if (AL.getKind() == ParsedAttr::AT_Annotate) { + ProcessDeclAttribute(*this, nullptr, ASDecl, AL, AL.isCXX11Attribute()); } else { - Diag(l->getLoc(), diag::err_only_annotate_after_access_spec); + Diag(AL.getLoc(), diag::err_only_annotate_after_access_spec); return true; } } - return false; } /// checkUnusedDeclAttributes - Check a list of attributes to see if it /// contains any decl attributes that we should warn about. -static void checkUnusedDeclAttributes(Sema &S, const AttributeList *A) { - for ( ; A; A = A->getNext()) { +static void checkUnusedDeclAttributes(Sema &S, const ParsedAttributesView &A) { + for (const ParsedAttr &AL : A) { // Only warn if the attribute is an unignored, non-type attribute. - if (A->isUsedAsTypeAttr() || A->isInvalid()) continue; - if (A->getKind() == AttributeList::IgnoredAttribute) continue; + if (AL.isUsedAsTypeAttr() || AL.isInvalid()) + continue; + if (AL.getKind() == ParsedAttr::IgnoredAttribute) + continue; - if (A->getKind() == AttributeList::UnknownAttribute) { - S.Diag(A->getLoc(), diag::warn_unknown_attribute_ignored) - << A->getName() << A->getRange(); + if (AL.getKind() == ParsedAttr::UnknownAttribute) { + S.Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) + << AL.getName() << AL.getRange(); } else { - S.Diag(A->getLoc(), diag::warn_attribute_not_on_decl) - << A->getName() << A->getRange(); + S.Diag(AL.getLoc(), diag::warn_attribute_not_on_decl) + << AL.getName() << AL.getRange(); } } } @@ -6687,7 +6721,7 @@ static void checkUnusedDeclAttributes(Sema &S, const AttributeList *A) { /// used to build a declaration, complain about any decl attributes /// which might be lying around on it. void Sema::checkUnusedDeclAttributes(Declarator &D) { - ::checkUnusedDeclAttributes(*this, D.getDeclSpec().getAttributes().getList()); + ::checkUnusedDeclAttributes(*this, D.getDeclSpec().getAttributes()); ::checkUnusedDeclAttributes(*this, D.getAttributes()); for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) ::checkUnusedDeclAttributes(*this, D.getTypeObject(i).getAttrs()); @@ -6699,7 +6733,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, SourceLocation Loc) { assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND)); NamedDecl *NewD = nullptr; - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { + if (auto *FD = dyn_cast<FunctionDecl>(ND)) { FunctionDecl *NewFD; // FIXME: Missing call to CheckFunctionDeclaration(). // FIXME: Mangling? @@ -6719,7 +6753,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, // Fake up parameter variables; they are declared as if this were // a typedef. QualType FDTy = FD->getType(); - if (const FunctionProtoType *FT = FDTy->getAs<FunctionProtoType>()) { + if (const auto *FT = FDTy->getAs<FunctionProtoType>()) { SmallVector<ParmVarDecl*, 16> Params; for (const auto &AI : FT->param_types()) { ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, Loc, AI); @@ -6728,15 +6762,13 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, } NewFD->setParams(Params); } - } else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) { + } else if (auto *VD = dyn_cast<VarDecl>(ND)) { NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(), VD->getInnerLocStart(), VD->getLocation(), II, VD->getType(), VD->getTypeSourceInfo(), VD->getStorageClass()); - if (VD->getQualifier()) { - VarDecl *NewVD = cast<VarDecl>(NewD); - NewVD->setQualifierInfo(VD->getQualifierLoc()); - } + if (VD->getQualifier()) + cast<VarDecl>(NewD)->setQualifierInfo(VD->getQualifierLoc()); } return NewD; } @@ -6772,10 +6804,10 @@ void Sema::ProcessPragmaWeak(Scope *S, Decl *D) { LoadExternalWeakUndeclaredIdentifiers(); if (!WeakUndeclaredIdentifiers.empty()) { NamedDecl *ND = nullptr; - if (VarDecl *VD = dyn_cast<VarDecl>(D)) + if (auto *VD = dyn_cast<VarDecl>(D)) if (VD->isExternC()) ND = VD; - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + if (auto *FD = dyn_cast<FunctionDecl>(D)) if (FD->isExternC()) ND = FD; if (ND) { @@ -6796,20 +6828,19 @@ void Sema::ProcessPragmaWeak(Scope *S, Decl *D) { /// specified in many different places, and we need to find and apply them all. void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { // Apply decl attributes from the DeclSpec if present. - if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes().getList()) - ProcessDeclAttributeList(S, D, Attrs); + if (!PD.getDeclSpec().getAttributes().empty()) + ProcessDeclAttributeList(S, D, PD.getDeclSpec().getAttributes()); // Walk the declarator structure, applying decl attributes that were in a type // position to the decl itself. This handles cases like: // int *__attr__(x)** D; // when X is a decl attribute. for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i) - if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs()) - ProcessDeclAttributeList(S, D, Attrs, /*IncludeCXX11Attributes=*/false); + ProcessDeclAttributeList(S, D, PD.getTypeObject(i).getAttrs(), + /*IncludeCXX11Attributes=*/false); // Finally, apply any attributes on the decl itself. - if (const AttributeList *Attrs = PD.getAttributes()) - ProcessDeclAttributeList(S, D, Attrs); + ProcessDeclAttributeList(S, D, PD.getAttributes()); // Apply additional attributes specified by '#pragma clang attribute'. AddPragmaAttributes(S, D); @@ -6818,14 +6849,14 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { /// Is the given declaration allowed to use a forbidden type? /// If so, it'll still be annotated with an attribute that makes it /// illegal to actually use. -static bool isForbiddenTypeAllowed(Sema &S, Decl *decl, +static bool isForbiddenTypeAllowed(Sema &S, Decl *D, const DelayedDiagnostic &diag, UnavailableAttr::ImplicitReason &reason) { // Private ivars are always okay. Unfortunately, people don't // always properly make their ivars private, even in system headers. // Plus we need to make fields okay, too. - if (!isa<FieldDecl>(decl) && !isa<ObjCPropertyDecl>(decl) && - !isa<FunctionDecl>(decl)) + if (!isa<FieldDecl>(D) && !isa<ObjCPropertyDecl>(D) && + !isa<FunctionDecl>(D)) return false; // Silently accept unsupported uses of __weak in both user and system @@ -6833,7 +6864,7 @@ static bool isForbiddenTypeAllowed(Sema &S, Decl *decl, // -fno-objc-arc files. We do have to take some care against attempts // to define such things; for now, we've only done that for ivars // and properties. - if ((isa<ObjCIvarDecl>(decl) || isa<ObjCPropertyDecl>(decl))) { + if ((isa<ObjCIvarDecl>(D) || isa<ObjCPropertyDecl>(D))) { if (diag.getForbiddenTypeDiagnostic() == diag::err_arc_weak_disabled || diag.getForbiddenTypeDiagnostic() == diag::err_arc_weak_no_runtime) { reason = UnavailableAttr::IR_ForbiddenWeak; @@ -6842,7 +6873,7 @@ static bool isForbiddenTypeAllowed(Sema &S, Decl *decl, } // Allow all sorts of things in system headers. - if (S.Context.getSourceManager().isInSystemHeader(decl->getLocation())) { + if (S.Context.getSourceManager().isInSystemHeader(D->getLocation())) { // Currently, all the failures dealt with this way are due to ARC // restrictions. reason = UnavailableAttr::IR_ARCForbiddenType; @@ -6853,30 +6884,29 @@ static bool isForbiddenTypeAllowed(Sema &S, Decl *decl, } /// Handle a delayed forbidden-type diagnostic. -static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag, - Decl *decl) { - auto reason = UnavailableAttr::IR_None; - if (decl && isForbiddenTypeAllowed(S, decl, diag, reason)) { - assert(reason && "didn't set reason?"); - decl->addAttr(UnavailableAttr::CreateImplicit(S.Context, "", reason, - diag.Loc)); +static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &DD, + Decl *D) { + auto Reason = UnavailableAttr::IR_None; + if (D && isForbiddenTypeAllowed(S, D, DD, Reason)) { + assert(Reason && "didn't set reason?"); + D->addAttr(UnavailableAttr::CreateImplicit(S.Context, "", Reason, DD.Loc)); return; } if (S.getLangOpts().ObjCAutoRefCount) - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(decl)) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { // FIXME: we may want to suppress diagnostics for all - // kind of forbidden type messages on unavailable functions. + // kind of forbidden type messages on unavailable functions. if (FD->hasAttr<UnavailableAttr>() && - diag.getForbiddenTypeDiagnostic() == - diag::err_arc_array_param_no_ownership) { - diag.Triggered = true; + DD.getForbiddenTypeDiagnostic() == + diag::err_arc_array_param_no_ownership) { + DD.Triggered = true; return; } } - S.Diag(diag.Loc, diag.getForbiddenTypeDiagnostic()) - << diag.getForbiddenTypeOperand() << diag.getForbiddenTypeArgument(); - diag.Triggered = true; + S.Diag(DD.Loc, DD.getForbiddenTypeDiagnostic()) + << DD.getForbiddenTypeOperand() << DD.getForbiddenTypeArgument(); + DD.Triggered = true; } static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, @@ -6919,9 +6949,9 @@ ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message) { // For typedefs, if the typedef declaration appears available look // to the underlying type to see if it is more restrictive. - while (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { + while (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { if (Result == AR_Available) { - if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) { + if (const auto *TT = TD->getUnderlyingType()->getAs<TagType>()) { D = TT->getDecl(); Result = D->getAvailability(Message); continue; @@ -6931,7 +6961,7 @@ ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message) { } // Forward class declarations get their attributes from their definition. - if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) { + if (const auto *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) { if (IDecl->getDefinition()) { D = IDecl->getDefinition(); Result = D->getAvailability(Message); @@ -6951,7 +6981,7 @@ ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message) { } -/// \brief whether we should emit a diagnostic for \c K and \c DeclVersion in +/// whether we should emit a diagnostic for \c K and \c DeclVersion in /// the context of \c Ctx. For example, we should emit an unavailable diagnostic /// in a deprecated context, but not the other way around. static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, @@ -6974,40 +7004,24 @@ static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, return false; }; - // FIXME: This is a temporary workaround! Some existing Apple headers depends - // on nested declarations in an @interface having the availability of the - // interface when they really shouldn't: they are members of the enclosing - // context, and can referenced from there. - if (S.OriginalLexicalContext && cast<Decl>(S.OriginalLexicalContext) != Ctx) { - auto *OrigCtx = cast<Decl>(S.OriginalLexicalContext); - if (CheckContext(OrigCtx)) - return false; - - // An implementation implicitly has the availability of the interface. - if (auto *CatOrImpl = dyn_cast<ObjCImplDecl>(OrigCtx)) { - if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface()) - if (CheckContext(Interface)) - return false; - } - // A category implicitly has the availability of the interface. - else if (auto *CatD = dyn_cast<ObjCCategoryDecl>(OrigCtx)) - if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface()) - if (CheckContext(Interface)) - return false; - } - do { if (CheckContext(Ctx)) return false; // An implementation implicitly has the availability of the interface. - if (auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) { + // Unless it is "+load" method. + if (const auto *MethodD = dyn_cast<ObjCMethodDecl>(Ctx)) + if (MethodD->isClassMethod() && + MethodD->getSelector().getAsString() == "load") + return true; + + if (const auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) { if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface()) if (CheckContext(Interface)) return false; } // A category implicitly has the availability of the interface. - else if (auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx)) + else if (const auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx)) if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface()) if (CheckContext(Interface)) return false; @@ -7077,6 +7091,45 @@ struct AttributeInsertion { } // end anonymous namespace +/// Tries to parse a string as ObjC method name. +/// +/// \param Name The string to parse. Expected to originate from availability +/// attribute argument. +/// \param SlotNames The vector that will be populated with slot names. In case +/// of unsuccessful parsing can contain invalid data. +/// \returns A number of method parameters if parsing was successful, None +/// otherwise. +static Optional<unsigned> +tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames, + const LangOptions &LangOpts) { + // Accept replacements starting with - or + as valid ObjC method names. + if (!Name.empty() && (Name.front() == '-' || Name.front() == '+')) + Name = Name.drop_front(1); + if (Name.empty()) + return None; + Name.split(SlotNames, ':'); + unsigned NumParams; + if (Name.back() == ':') { + // Remove an empty string at the end that doesn't represent any slot. + SlotNames.pop_back(); + NumParams = SlotNames.size(); + } else { + if (SlotNames.size() != 1) + // Not a valid method name, just a colon-separated string. + return None; + NumParams = 0; + } + // Verify all slot names are valid. + bool AllowDollar = LangOpts.DollarIdents; + for (StringRef S : SlotNames) { + if (S.empty()) + continue; + if (!isValidIdentifier(S, AllowDollar)) + return None; + } + return NumParams; +} + /// Returns a source location in which it's appropriate to insert a new /// attribute for the given declaration \D. static Optional<AttributeInsertion> @@ -7106,14 +7159,15 @@ createAttributeInsertion(const NamedDecl *D, const SourceManager &SM, /// \param Ctx The context that the reference occurred in /// \param ReferringDecl The exact declaration that was referenced. /// \param OffendingDecl A related decl to \c ReferringDecl that has an -/// availability attribute corrisponding to \c K attached to it. Note that this +/// availability attribute corresponding to \c K attached to it. Note that this /// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and /// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl /// and OffendingDecl is the EnumDecl. static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, Decl *Ctx, const NamedDecl *ReferringDecl, const NamedDecl *OffendingDecl, - StringRef Message, SourceLocation Loc, + StringRef Message, + ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { @@ -7135,6 +7189,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx)) return; + SourceLocation Loc = Locs.front(); + // The declaration can have multiple availability attributes, we are looking // at one of them. const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl); @@ -7178,7 +7234,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, << OffendingDecl << /* partial */ 3; if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) { - if (auto *TD = dyn_cast<TagDecl>(Enclosing)) + if (const auto *TD = dyn_cast<TagDecl>(Enclosing)) if (TD->getDeclName().isEmpty()) { S.Diag(TD->getLocation(), diag::note_decl_unguarded_availability_silence) @@ -7219,8 +7275,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, diag_fwdclass_message = diag::warn_deprecated_fwdclass_message; property_note_select = /* deprecated */ 0; available_here_select_kind = /* deprecated */ 2; - if (const auto *Attr = OffendingDecl->getAttr<DeprecatedAttr>()) - NoteLocation = Attr->getLocation(); + if (const auto *AL = OffendingDecl->getAttr<DeprecatedAttr>()) + NoteLocation = AL->getLocation(); break; case AR_Unavailable: @@ -7231,8 +7287,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, property_note_select = /* unavailable */ 1; available_here_select_kind = /* unavailable */ 0; - if (auto Attr = OffendingDecl->getAttr<UnavailableAttr>()) { - if (Attr->isImplicit() && Attr->getImplicitReason()) { + if (auto AL = OffendingDecl->getAttr<UnavailableAttr>()) { + if (AL->isImplicit() && AL->getImplicitReason()) { // Most of these failures are due to extra restrictions in ARC; // reflect that in the primary diagnostic when applicable. auto flagARCError = [&] { @@ -7242,7 +7298,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, diag = diag::err_unavailable_in_arc; }; - switch (Attr->getImplicitReason()) { + switch (AL->getImplicitReason()) { case UnavailableAttr::IR_None: break; case UnavailableAttr::IR_ARCForbiddenType: @@ -7280,37 +7336,55 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, llvm_unreachable("Warning for availability of available declaration?"); } - CharSourceRange UseRange; - StringRef Replacement; + SmallVector<FixItHint, 12> FixIts; if (K == AR_Deprecated) { - if (auto Attr = OffendingDecl->getAttr<DeprecatedAttr>()) - Replacement = Attr->getReplacement(); - if (auto Attr = getAttrForPlatform(S.Context, OffendingDecl)) - Replacement = Attr->getReplacement(); + StringRef Replacement; + if (auto AL = OffendingDecl->getAttr<DeprecatedAttr>()) + Replacement = AL->getReplacement(); + if (auto AL = getAttrForPlatform(S.Context, OffendingDecl)) + Replacement = AL->getReplacement(); + CharSourceRange UseRange; if (!Replacement.empty()) UseRange = CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc)); + if (UseRange.isValid()) { + if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) { + Selector Sel = MethodDecl->getSelector(); + SmallVector<StringRef, 12> SelectorSlotNames; + Optional<unsigned> NumParams = tryParseObjCMethodName( + Replacement, SelectorSlotNames, S.getLangOpts()); + if (NumParams && NumParams.getValue() == Sel.getNumArgs()) { + assert(SelectorSlotNames.size() == Locs.size()); + for (unsigned I = 0; I < Locs.size(); ++I) { + if (!Sel.getNameForSlot(I).empty()) { + CharSourceRange NameRange = CharSourceRange::getCharRange( + Locs[I], S.getLocForEndOfToken(Locs[I])); + FixIts.push_back(FixItHint::CreateReplacement( + NameRange, SelectorSlotNames[I])); + } else + FixIts.push_back( + FixItHint::CreateInsertion(Locs[I], SelectorSlotNames[I])); + } + } else + FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement)); + } else + FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement)); + } } if (!Message.empty()) { - S.Diag(Loc, diag_message) << ReferringDecl << Message - << (UseRange.isValid() ? - FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); + S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts; if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else if (!UnknownObjCClass) { - S.Diag(Loc, diag) << ReferringDecl - << (UseRange.isValid() ? - FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); + S.Diag(Loc, diag) << ReferringDecl << FixIts; if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else { - S.Diag(Loc, diag_fwdclass_message) << ReferringDecl - << (UseRange.isValid() ? - FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); + S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts; S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); } @@ -7326,8 +7400,9 @@ static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, DD.Triggered = true; DoEmitAvailabilityWarning( S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(), - DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), DD.Loc, - DD.getUnknownObjCClass(), DD.getObjCProperty(), false); + DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), + DD.getAvailabilitySelectorLocs(), DD.getUnknownObjCClass(), + DD.getObjCProperty(), false); } void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { @@ -7388,7 +7463,8 @@ void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) { static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR, const NamedDecl *ReferringDecl, const NamedDecl *OffendingDecl, - StringRef Message, SourceLocation Loc, + StringRef Message, + ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { @@ -7396,14 +7472,14 @@ static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR, if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { S.DelayedDiagnostics.add( DelayedDiagnostic::makeAvailability( - AR, Loc, ReferringDecl, OffendingDecl, UnknownObjCClass, + AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass, ObjCProperty, Message, ObjCPropertyAccess)); return; } Decl *Ctx = cast<Decl>(S.getCurLexicalContext()); DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl, - Message, Loc, UnknownObjCClass, ObjCProperty, + Message, Locs, UnknownObjCClass, ObjCProperty, ObjCPropertyAccess); } @@ -7472,7 +7548,7 @@ public: } }; -/// \brief This class implements -Wunguarded-availability. +/// This class implements -Wunguarded-availability. /// /// This is done with a traversal of the AST of a function that makes reference /// to a partially available declaration. Whenever we encounter an \c if of the @@ -7643,7 +7719,7 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( SourceLocation StmtEndLoc = SM.getExpansionRange( (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getLocEnd()) - .second; + .getEnd(); if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc)) return; @@ -7682,11 +7758,11 @@ bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) { if (Range.isInvalid()) return true; - if (const TagType *TT = dyn_cast<TagType>(TyPtr)) { + if (const auto *TT = dyn_cast<TagType>(TyPtr)) { TagDecl *TD = TT->getDecl(); DiagnoseDeclAvailability(TD, Range); - } else if (const TypedefType *TD = dyn_cast<TypedefType>(TyPtr)) { + } else if (const auto *TD = dyn_cast<TypedefType>(TyPtr)) { TypedefNameDecl *D = TD->getDecl(); DiagnoseDeclAvailability(D, Range); @@ -7741,7 +7817,8 @@ void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) { DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body); } -void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc, +void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, + ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks) { @@ -7770,7 +7847,7 @@ void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc, } const ObjCPropertyDecl *ObjCPDecl = nullptr; - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { AvailabilityResult PDeclResult = PD->getAvailability(nullptr); if (PDeclResult == Result) @@ -7778,6 +7855,6 @@ void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc, } } - EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Loc, + EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Locs, UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess); } |