diff options
Diffstat (limited to 'clang/lib')
56 files changed, 1066 insertions, 312 deletions
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 0f2762d..f113b32 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -870,7 +870,29 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, else if (T1->getTypeClass() == Type::FunctionNoProto && T2->getTypeClass() == Type::FunctionProto) TC = Type::FunctionNoProto; - else + else if (Context.LangOpts.C23 && !Context.StrictTypeSpelling && + (T1->getTypeClass() == Type::Enum || + T2->getTypeClass() == Type::Enum)) { + // In C23, if not being strict about token equivalence, we need to handle + // the case where one type is an enumeration and the other type is an + // integral type. + // + // C23 6.7.3.3p16: The enumerated type is compatible with the underlying + // type of the enumeration. + // + // Treat the enumeration as its underlying type and use the builtin type + // class comparison. + if (T1->getTypeClass() == Type::Enum) { + T1 = T1->getAs<EnumType>()->getDecl()->getIntegerType(); + if (!T2->isBuiltinType() || T1.isNull()) // Sanity check + return false; + } else if (T2->getTypeClass() == Type::Enum) { + T2 = T2->getAs<EnumType>()->getDecl()->getIntegerType(); + if (!T1->isBuiltinType() || T2.isNull()) // Sanity check + return false; + } + TC = Type::Builtin; + } else return false; } diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 63ac536..d0ddb2e 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -1022,7 +1022,8 @@ bool Compiler<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) { if (classifyPrim(E) != PT_Ptr) return this->emitDecayPtr(PT_Ptr, classifyPrim(E), E); return true; - } else if (Op == BO_Sub) { + } + if (Op == BO_Sub) { if (!this->emitSubOffset(OffsetType, E)) return false; @@ -3703,7 +3704,7 @@ bool Compiler<Emitter>::VisitBlockExpr(const BlockExpr *E) { return true; const Function *Func = nullptr; - if (auto F = Ctx.getOrCreateObjCBlock(E)) + if (const Function *F = Ctx.getOrCreateObjCBlock(E)) Func = F; if (!Func) @@ -4288,7 +4289,8 @@ bool Compiler<Emitter>::visitZeroArrayInitializer(QualType T, const Expr *E) { return false; } return true; - } else if (ElemType->isRecordType()) { + } + if (ElemType->isRecordType()) { const Record *R = getRecord(ElemType); for (size_t I = 0; I != NumElems; ++I) { @@ -4302,7 +4304,8 @@ bool Compiler<Emitter>::visitZeroArrayInitializer(QualType T, const Expr *E) { return false; } return true; - } else if (ElemType->isArrayType()) { + } + if (ElemType->isArrayType()) { for (size_t I = 0; I != NumElems; ++I) { if (!this->emitConstUint32(I, E)) return false; @@ -4774,11 +4777,10 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD, if (!this->visit(Init)) return false; return this->emitSetLocal(*VarT, Offset, VD) && Scope.destroyLocals(); - } else { + } if (!this->visit(Init)) return false; return this->emitSetLocal(*VarT, Offset, VD); - } } } else { if (std::optional<unsigned> Offset = this->allocateLocal( @@ -4805,7 +4807,7 @@ bool Compiler<Emitter>::visitAPValue(const APValue &Val, PrimType ValType, assert(!DiscardResult); if (Val.isInt()) return this->emitConst(Val.getInt(), ValType, E); - else if (Val.isFloat()) { + if (Val.isFloat()) { APFloat F = Val.getFloat(); return this->emitFloat(F, E); } @@ -4816,9 +4818,8 @@ bool Compiler<Emitter>::visitAPValue(const APValue &Val, PrimType ValType, APValue::LValueBase Base = Val.getLValueBase(); if (const Expr *BaseExpr = Base.dyn_cast<const Expr *>()) return this->visit(BaseExpr); - else if (const auto *VD = Base.dyn_cast<const ValueDecl *>()) { + if (const auto *VD = Base.dyn_cast<const ValueDecl *>()) return this->visitDeclRef(VD, E); - } } else if (Val.isMemberPointer()) { if (const ValueDecl *MemberDecl = Val.getMemberPointerDecl()) return this->emitGetMemberPtr(MemberDecl, E); @@ -4854,7 +4855,8 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val, } } return true; - } else if (Val.isUnion()) { + } + if (Val.isUnion()) { const FieldDecl *UnionField = Val.getUnionField(); const Record *R = this->getRecord(UnionField->getParent()); assert(R); @@ -4864,7 +4866,8 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val, if (!this->visitAPValue(F, T, E)) return false; return this->emitInitField(T, RF->Offset, E); - } else if (Val.isArray()) { + } + if (Val.isArray()) { const auto *ArrType = T->getAsArrayTypeUnsafe(); QualType ElemType = ArrType->getElementType(); for (unsigned A = 0, AN = Val.getArraySize(); A != AN; ++A) { @@ -4981,12 +4984,10 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { // Calls to replaceable operator new/operator delete. if (FuncDecl->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) { - if (FuncDecl->getDeclName().isAnyOperatorNew()) { + if (FuncDecl->getDeclName().isAnyOperatorNew()) return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_new); - } else { - assert(FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_Delete); - return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_delete); - } + assert(FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_Delete); + return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_delete); } // Explicit calls to trivial destructors @@ -5455,7 +5456,9 @@ bool Compiler<Emitter>::visitReturnStmt(const ReturnStmt *RS) { return false; this->emitCleanup(); return this->emitRet(*ReturnType, RS); - } else if (RE->getType()->isVoidType()) { + } + + if (RE->getType()->isVoidType()) { if (!this->visit(RE)) return false; } else { @@ -5500,7 +5503,7 @@ template <class Emitter> bool Compiler<Emitter>::visitIfStmt(const IfStmt *IS) { if (std::optional<bool> BoolValue = getBoolValue(IS->getCond())) { if (*BoolValue) return visitChildStmt(IS->getThen()); - else if (const Stmt *Else = IS->getElse()) + if (const Stmt *Else = IS->getElse()) return visitChildStmt(Else); return true; } @@ -5992,7 +5995,7 @@ bool Compiler<Emitter>::compileConstructor(const CXXConstructorDecl *Ctor) { if (!this->emitThis(Ctor)) return false; - auto PVD = Ctor->getParamDecl(0); + const ParmVarDecl *PVD = Ctor->getParamDecl(0); ParamOffset PO = this->Params[PVD]; // Must exist. if (!this->emitGetParam(PT_Ptr, PO.Offset, Ctor)) @@ -6153,7 +6156,7 @@ bool Compiler<Emitter>::compileUnionAssignmentOperator( if (!this->emitThis(MD)) return false; - auto PVD = MD->getParamDecl(0); + const ParmVarDecl *PVD = MD->getParamDecl(0); ParamOffset PO = this->Params[PVD]; // Must exist. if (!this->emitGetParam(PT_Ptr, PO.Offset, MD)) diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 5463aec..224d65c 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -845,7 +845,7 @@ bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { return true; } -bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { +static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) { const SourceLocation &Loc = S.Current->getLocation(OpPC); diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 19d4c0c..3ece7054 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -240,9 +240,9 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC, T CB = PB.deref<T>(); if (CA > CB) return returnResult(1); - else if (CA < CB) + if (CA < CB) return returnResult(-1); - else if (CA.isZero() || CB.isZero()) + if (CA.isZero() || CB.isZero()) return returnResult(0); }); continue; @@ -253,7 +253,7 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC, if (CA > CB) return returnResult(1); - else if (CA < CB) + if (CA < CB) return returnResult(-1); if (CA == 0 || CB == 0) return returnResult(0); @@ -1048,7 +1048,7 @@ static bool interp__builtin_atomic_lock_free(InterpState &S, CodePtr OpPC, PtrArg = ICE->getSubExpr(); } - if (auto PtrTy = PtrArg->getType()->getAs<PointerType>()) { + if (const auto *PtrTy = PtrArg->getType()->getAs<PointerType>()) { QualType PointeeType = PtrTy->getPointeeType(); if (!PointeeType->isIncompleteType() && S.getASTContext().getTypeAlignInChars(PointeeType) >= Size) { @@ -1967,7 +1967,8 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC, if (A < B) { pushInteger(S, -1, Call->getType()); return true; - } else if (A > B) { + } + if (A > B) { pushInteger(S, 1, Call->getType()); return true; } @@ -1979,7 +1980,8 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC, if (A < B) { pushInteger(S, -1, Call->getType()); return true; - } else if (A > B) { + } + if (A > B) { pushInteger(S, 1, Call->getType()); return true; } diff --git a/clang/lib/AST/ByteCode/InterpStack.h b/clang/lib/AST/ByteCode/InterpStack.h index 0b76f1d..580494e 100644 --- a/clang/lib/AST/ByteCode/InterpStack.h +++ b/clang/lib/AST/ByteCode/InterpStack.h @@ -14,11 +14,9 @@ #define LLVM_CLANG_AST_INTERP_INTERPSTACK_H #include "FixedPoint.h" -#include "FunctionPointer.h" #include "IntegralAP.h" #include "MemberPointer.h" #include "PrimType.h" -#include <memory> #include <vector> namespace clang { diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index 4019b74..9341bc1 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -16,6 +16,7 @@ #include "MemberPointer.h" #include "PrimType.h" #include "Record.h" +#include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/RecordLayout.h" @@ -66,14 +67,14 @@ Pointer::~Pointer() { } } -void Pointer::operator=(const Pointer &P) { +Pointer &Pointer::operator=(const Pointer &P) { // If the current storage type is Block, we need to remove // this pointer from the block. if (isBlockPointer()) { if (P.isBlockPointer() && this->block() == P.block()) { Offset = P.Offset; PointeeStorage.BS.Base = P.PointeeStorage.BS.Base; - return; + return *this; } if (Block *Pointee = PointeeStorage.BS.Pointee) { @@ -101,16 +102,17 @@ void Pointer::operator=(const Pointer &P) { } else { assert(false && "Unhandled storage kind"); } + return *this; } -void Pointer::operator=(Pointer &&P) { +Pointer &Pointer::operator=(Pointer &&P) { // If the current storage type is Block, we need to remove // this pointer from the block. if (isBlockPointer()) { if (P.isBlockPointer() && this->block() == P.block()) { Offset = P.Offset; PointeeStorage.BS.Base = P.PointeeStorage.BS.Base; - return; + return *this; } if (Block *Pointee = PointeeStorage.BS.Pointee) { @@ -138,6 +140,7 @@ void Pointer::operator=(Pointer &&P) { } else { assert(false && "Unhandled storage kind"); } + return *this; } APValue Pointer::toAPValue(const ASTContext &ASTCtx) const { @@ -603,7 +606,7 @@ bool Pointer::pointsToStringLiteral() const { return false; const Expr *E = block()->getDescriptor()->asExpr(); - return E && isa<StringLiteral>(E); + return isa_and_nonnull<StringLiteral>(E); } std::optional<std::pair<Pointer, Pointer>> diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index d17eba5..059f176 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -120,8 +120,8 @@ public: Pointer(Block *Pointee, unsigned Base, uint64_t Offset); ~Pointer(); - void operator=(const Pointer &P); - void operator=(Pointer &&P); + Pointer &operator=(const Pointer &P); + Pointer &operator=(Pointer &&P); /// Equality operators are just for tests. bool operator==(const Pointer &P) const { @@ -761,7 +761,7 @@ public: if (Offset < Other.Offset) return ComparisonCategoryResult::Less; - else if (Offset > Other.Offset) + if (Offset > Other.Offset) return ComparisonCategoryResult::Greater; return ComparisonCategoryResult::Equal; diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index 7002724..2421ec4 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -418,7 +418,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, } return allocateDescriptor(D, *T, MDSize, NumElems, IsConst, IsTemporary, IsMutable); - } else { + } // Arrays of composites. In this case, the array is a list of pointers, // followed by the actual elements. const Descriptor *ElemDesc = createDescriptor( @@ -430,7 +430,6 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, return {}; return allocateDescriptor(D, Ty, ElemDesc, MDSize, NumElems, IsConst, IsTemporary, IsMutable); - } } // Array of unknown bounds - cannot be accessed and pointer arithmetic @@ -440,14 +439,13 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, if (OptPrimType T = Ctx.classify(ElemTy)) { return allocateDescriptor(D, *T, MDSize, IsConst, IsTemporary, Descriptor::UnknownSize{}); - } else { + } const Descriptor *Desc = createDescriptor( D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary); if (!Desc) return nullptr; return allocateDescriptor(D, Desc, MDSize, IsTemporary, Descriptor::UnknownSize{}); - } } } diff --git a/clang/lib/AST/ByteCode/Program.h b/clang/lib/AST/ByteCode/Program.h index 5d9c422..207ceef 100644 --- a/clang/lib/AST/ByteCode/Program.h +++ b/clang/lib/AST/ByteCode/Program.h @@ -19,10 +19,7 @@ #include "Record.h" #include "Source.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/PointerUnion.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" -#include <map> #include <vector> namespace clang { diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 2e1a9a3..d85655b 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1629,20 +1629,20 @@ QualType CallExpr::getCallReturnType(const ASTContext &Ctx) const { return FnType->getReturnType(); } -std::pair<const NamedDecl *, const Attr *> -CallExpr::getUnusedResultAttr(const ASTContext &Ctx) const { +std::pair<const NamedDecl *, const WarnUnusedResultAttr *> +Expr::getUnusedResultAttrImpl(const Decl *Callee, QualType ReturnType) { // If the callee is marked nodiscard, return that attribute - if (const Decl *D = getCalleeDecl()) - if (const auto *A = D->getAttr<WarnUnusedResultAttr>()) + if (Callee != nullptr) + if (const auto *A = Callee->getAttr<WarnUnusedResultAttr>()) return {nullptr, A}; // If the return type is a struct, union, or enum that is marked nodiscard, // then return the return type attribute. - if (const TagDecl *TD = getCallReturnType(Ctx)->getAsTagDecl()) + if (const TagDecl *TD = ReturnType->getAsTagDecl()) if (const auto *A = TD->getAttr<WarnUnusedResultAttr>()) return {TD, A}; - for (const auto *TD = getCallReturnType(Ctx)->getAs<TypedefType>(); TD; + for (const auto *TD = ReturnType->getAs<TypedefType>(); TD; TD = TD->desugar()->getAs<TypedefType>()) if (const auto *A = TD->getDecl()->getAttr<WarnUnusedResultAttr>()) return {TD->getDecl(), A}; @@ -2844,12 +2844,11 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, return true; } - if (const ObjCMethodDecl *MD = ME->getMethodDecl()) - if (MD->hasAttr<WarnUnusedResultAttr>()) { - WarnE = this; - Loc = getExprLoc(); - return true; - } + if (ME->hasUnusedResultAttr(Ctx)) { + WarnE = this; + Loc = getExprLoc(); + return true; + } return false; } diff --git a/clang/lib/AST/ExprObjC.cpp b/clang/lib/AST/ExprObjC.cpp index 50d3a447..83419a1 100644 --- a/clang/lib/AST/ExprObjC.cpp +++ b/clang/lib/AST/ExprObjC.cpp @@ -12,6 +12,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/ComputeDependence.h" #include "clang/AST/SelectorLocationsKind.h" #include "clang/AST/Type.h" diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp index fc4ec78..7481e1e 100644 --- a/clang/lib/Basic/FileManager.cpp +++ b/clang/lib/Basic/FileManager.cpp @@ -368,11 +368,6 @@ void FileManager::trackVFSUsage(bool Active) { }); } -const FileEntry *FileManager::getVirtualFile(StringRef Filename, off_t Size, - time_t ModificationTime) { - return &getVirtualFileRef(Filename, Size, ModificationTime).getFileEntry(); -} - FileEntryRef FileManager::getVirtualFileRef(StringRef Filename, off_t Size, time_t ModificationTime) { ++NumFileLookups; diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp index cebcfa3..52cbdbc 100644 --- a/clang/lib/Basic/Targets/AMDGPU.cpp +++ b/clang/lib/Basic/Targets/AMDGPU.cpp @@ -266,8 +266,11 @@ AMDGPUTargetInfo::AMDGPUTargetInfo(const llvm::Triple &Triple, MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; CUMode = !(GPUFeatures & llvm::AMDGPU::FEATURE_WGP); - for (auto F : {"image-insts", "gws", "vmem-to-lds-load-insts"}) - ReadOnlyFeatures.insert(F); + + for (auto F : {"image-insts", "gws", "vmem-to-lds-load-insts"}) { + if (GPUKind != llvm::AMDGPU::GK_NONE) + ReadOnlyFeatures.insert(F); + } HalfArgsAndReturns = true; } diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp index 29de34bb..6bec2fa 100644 --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -618,21 +618,21 @@ bool ARMTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, LDREX = 0; else if (ArchKind == llvm::ARM::ArchKind::ARMV6K || ArchKind == llvm::ARM::ArchKind::ARMV6KZ) - LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B; + LDREX = ARM_LDREX_D | ARM_LDREX_W | ARM_LDREX_H | ARM_LDREX_B; else - LDREX = LDREX_W; + LDREX = ARM_LDREX_W; break; case 7: case 8: if (ArchProfile == llvm::ARM::ProfileKind::M) - LDREX = LDREX_W | LDREX_H | LDREX_B; + LDREX = ARM_LDREX_W | ARM_LDREX_H | ARM_LDREX_B; else - LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B; + LDREX = ARM_LDREX_D | ARM_LDREX_W | ARM_LDREX_H | ARM_LDREX_B; break; case 9: assert(ArchProfile != llvm::ARM::ProfileKind::M && "No Armv9-M architectures defined"); - LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B; + LDREX = ARM_LDREX_D | ARM_LDREX_W | ARM_LDREX_H | ARM_LDREX_B; } if (!(FPU & NeonFPU) && FPMath == FP_Neon) { diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h index 1719217..43c4718 100644 --- a/clang/lib/Basic/Targets/ARM.h +++ b/clang/lib/Basic/Targets/ARM.h @@ -98,13 +98,6 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo { LLVM_PREFERRED_TYPE(bool) unsigned HasBTI : 1; - enum { - LDREX_B = (1 << 0), /// byte (8-bit) - LDREX_H = (1 << 1), /// half (16-bit) - LDREX_W = (1 << 2), /// word (32-bit) - LDREX_D = (1 << 3), /// double (64-bit) - }; - uint32_t LDREX; // ACLE 6.5.1 Hardware floating point @@ -225,6 +218,8 @@ public: bool hasBitIntType() const override { return true; } + unsigned getARMLDREXMask() const override { return LDREX; } + const char *getBFloat16Mangling() const override { return "u6__bf16"; }; std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override { diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index ef136f8..9049a01 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -190,6 +190,11 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, assert(!cir::MissingFeatures::builtinCheckKind()); return emitBuiltinBitOp<cir::BitClzOp>(*this, e, /*poisonZero=*/true); + case Builtin::BI__builtin_ffs: + case Builtin::BI__builtin_ffsl: + case Builtin::BI__builtin_ffsll: + return emitBuiltinBitOp<cir::BitFfsOp>(*this, e); + case Builtin::BI__builtin_parity: case Builtin::BI__builtin_parityl: case Builtin::BI__builtin_parityll: diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 7ff5f26..64dc1ce 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -949,7 +949,6 @@ LValue CIRGenFunction::emitCastLValue(const CastExpr *e) { case CK_Dynamic: case CK_ToUnion: case CK_BaseToDerived: - case CK_LValueBitCast: case CK_AddressSpaceConversion: case CK_ObjCObjectLValueCast: case CK_VectorSplat: @@ -965,6 +964,18 @@ LValue CIRGenFunction::emitCastLValue(const CastExpr *e) { return {}; } + case CK_LValueBitCast: { + // This must be a reinterpret_cast (or c-style equivalent). + const auto *ce = cast<ExplicitCastExpr>(e); + + cgm.emitExplicitCastExprType(ce, this); + LValue LV = emitLValue(e->getSubExpr()); + Address V = LV.getAddress().withElementType( + builder, convertTypeForMem(ce->getTypeAsWritten()->getPointeeType())); + + return makeAddrLValue(V, e->getType(), LV.getBaseInfo()); + } + case CK_NoOp: { // CK_NoOp can model a qualification conversion, which can remove an array // bound and change the IR type. diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp index 02685a3..a09d739 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp @@ -189,8 +189,11 @@ mlir::Value ComplexExprEmitter::emitCast(CastKind ck, Expr *op, } case CK_LValueBitCast: { - cgf.cgm.errorNYI("ComplexExprEmitter::emitCast CK_LValueBitCast"); - return {}; + LValue origLV = cgf.emitLValue(op); + Address addr = + origLV.getAddress().withElementType(builder, cgf.convertType(destTy)); + LValue destLV = cgf.makeAddrLValue(addr, destTy); + return emitLoadOfLValue(destLV, op->getExprLoc()); } case CK_LValueToRValueBitCast: { diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index b4b95d6..c65d025 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -923,4 +923,130 @@ CIRGenFunction::emitArrayLength(const clang::ArrayType *origArrayType, return builder.getConstInt(*currSrcLoc, SizeTy, countFromCLAs); } +// TODO(cir): Most of this function can be shared between CIRGen +// and traditional LLVM codegen +void CIRGenFunction::emitVariablyModifiedType(QualType type) { + assert(type->isVariablyModifiedType() && + "Must pass variably modified type to EmitVLASizes!"); + + // We're going to walk down into the type and look for VLA + // expressions. + do { + assert(type->isVariablyModifiedType()); + + const Type *ty = type.getTypePtr(); + switch (ty->getTypeClass()) { + case Type::CountAttributed: + case Type::PackIndexing: + case Type::ArrayParameter: + case Type::HLSLAttributedResource: + case Type::HLSLInlineSpirv: + case Type::PredefinedSugar: + cgm.errorNYI("CIRGenFunction::emitVariablyModifiedType"); + +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) case Type::Class: +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.inc" + llvm_unreachable( + "dependent type must be resolved before the CIR codegen"); + + // These types are never variably-modified. + case Type::Builtin: + case Type::Complex: + case Type::Vector: + case Type::ExtVector: + case Type::ConstantMatrix: + case Type::Record: + case Type::Enum: + case Type::Using: + case Type::TemplateSpecialization: + case Type::ObjCTypeParam: + case Type::ObjCObject: + case Type::ObjCInterface: + case Type::ObjCObjectPointer: + case Type::BitInt: + llvm_unreachable("type class is never variably-modified!"); + + case Type::Elaborated: + type = cast<clang::ElaboratedType>(ty)->getNamedType(); + break; + + case Type::Adjusted: + type = cast<clang::AdjustedType>(ty)->getAdjustedType(); + break; + + case Type::Decayed: + type = cast<clang::DecayedType>(ty)->getPointeeType(); + break; + + case Type::Pointer: + type = cast<clang::PointerType>(ty)->getPointeeType(); + break; + + case Type::BlockPointer: + type = cast<clang::BlockPointerType>(ty)->getPointeeType(); + break; + + case Type::LValueReference: + case Type::RValueReference: + type = cast<clang::ReferenceType>(ty)->getPointeeType(); + break; + + case Type::MemberPointer: + type = cast<clang::MemberPointerType>(ty)->getPointeeType(); + break; + + case Type::ConstantArray: + case Type::IncompleteArray: + // Losing element qualification here is fine. + type = cast<clang::ArrayType>(ty)->getElementType(); + break; + + case Type::VariableArray: { + cgm.errorNYI("CIRGenFunction::emitVariablyModifiedType VLA"); + break; + } + + case Type::FunctionProto: + case Type::FunctionNoProto: + type = cast<clang::FunctionType>(ty)->getReturnType(); + break; + + case Type::Paren: + case Type::TypeOf: + case Type::UnaryTransform: + case Type::Attributed: + case Type::BTFTagAttributed: + case Type::SubstTemplateTypeParm: + case Type::MacroQualified: + // Keep walking after single level desugaring. + type = type.getSingleStepDesugaredType(getContext()); + break; + + case Type::Typedef: + case Type::Decltype: + case Type::Auto: + case Type::DeducedTemplateSpecialization: + // Stop walking: nothing to do. + return; + + case Type::TypeOfExpr: + // Stop walking: emit typeof expression. + emitIgnoredExpr(cast<clang::TypeOfExprType>(ty)->getUnderlyingExpr()); + return; + + case Type::Atomic: + type = cast<clang::AtomicType>(ty)->getValueType(); + break; + + case Type::Pipe: + type = cast<clang::PipeType>(ty)->getElementType(); + break; + } + } while (type->isVariablyModifiedType()); +} + } // namespace clang::CIRGen diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 4891c74..77539d7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1201,6 +1201,8 @@ public: /// inside a function, including static vars etc. void emitVarDecl(const clang::VarDecl &d); + void emitVariablyModifiedType(QualType ty); + mlir::LogicalResult emitWhileStmt(const clang::WhileStmt &s); /// Given an assignment `*lhs = rhs`, emit a test that checks if \p rhs is diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 3502705..0724cb1 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -1208,6 +1208,15 @@ cir::GlobalOp CIRGenModule::getGlobalForStringLiteral(const StringLiteral *s, return gv; } +void CIRGenModule::emitExplicitCastExprType(const ExplicitCastExpr *e, + CIRGenFunction *cgf) { + if (cgf && e->getType()->isVariablyModifiedType()) + cgf->emitVariablyModifiedType(e->getType()); + + assert(!cir::MissingFeatures::generateDebugInfo() && + "emitExplicitCastExprType"); +} + void CIRGenModule::emitDeclContext(const DeclContext *dc) { for (Decl *decl : dc->decls()) { // Unlike other DeclContexts, the contents of an ObjCImplDecl at TU scope diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 16922b1..22519ff 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -252,6 +252,11 @@ public: getAddrOfGlobal(clang::GlobalDecl gd, ForDefinition_t isForDefinition = NotForDefinition); + /// Emit type info if type of an expression is a variably modified + /// type. Also emit proper debug info for cast types. + void emitExplicitCastExprType(const ExplicitCastExpr *e, + CIRGenFunction *cgf = nullptr); + /// Emit code for a single global function or variable declaration. Forward /// declarations are emitted lazily. void emitGlobal(clang::GlobalDecl gd); diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp index 05e8848..e4ec380 100644 --- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp @@ -438,9 +438,7 @@ CIRRecordLowering::accumulateBitFields(RecordDecl::field_iterator field, } else if (cirGenTypes.getCGModule() .getCodeGenOpts() .FineGrainedBitfieldAccesses) { - assert(!cir::MissingFeatures::nonFineGrainedBitfields()); - cirGenTypes.getCGModule().errorNYI(field->getSourceRange(), - "NYI FineGrainedBitfield"); + installBest = true; } else { // Otherwise, we're not installing. Update the bit size // of the current span to go all the way to limitOffset, which is diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 2213c75..35408bf 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2295,6 +2295,15 @@ OpFoldResult BitCtzOp::fold(FoldAdaptor adaptor) { getPoisonZero()); } +OpFoldResult BitFfsOp::fold(FoldAdaptor adaptor) { + return foldUnaryBitOp(adaptor.getInput(), [](const llvm::APInt &inputValue) { + unsigned trailingZeros = inputValue.countTrailingZeros(); + unsigned result = + trailingZeros == inputValue.getBitWidth() ? 0 : trailingZeros + 1; + return llvm::APInt(inputValue.getBitWidth(), result); + }); +} + OpFoldResult BitParityOp::fold(FoldAdaptor adaptor) { return foldUnaryBitOp(adaptor.getInput(), [](const llvm::APInt &inputValue) { return llvm::APInt(inputValue.getBitWidth(), inputValue.popcount() % 2); diff --git a/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp index 2143f16..2eaa60c 100644 --- a/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp @@ -143,7 +143,7 @@ void CIRCanonicalizePass::runOnOperation() { if (isa<BrOp, BrCondOp, CastOp, ScopeOp, SwitchOp, SelectOp, UnaryOp, ComplexCreateOp, ComplexImagOp, ComplexRealOp, VecCmpOp, VecCreateOp, VecExtractOp, VecShuffleOp, VecShuffleDynamicOp, - VecTernaryOp, BitClrsbOp, BitClzOp, BitCtzOp, BitParityOp, + VecTernaryOp, BitClrsbOp, BitClzOp, BitCtzOp, BitFfsOp, BitParityOp, BitPopcountOp, BitReverseOp, ByteSwapOp, RotateOp>(op)) ops.push_back(op); }); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index c27b889..0ed632f 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -521,6 +521,32 @@ mlir::LogicalResult CIRToLLVMBitCtzOpLowering::matchAndRewrite( return mlir::LogicalResult::success(); } +mlir::LogicalResult CIRToLLVMBitFfsOpLowering::matchAndRewrite( + cir::BitFfsOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + auto resTy = getTypeConverter()->convertType(op.getType()); + auto ctz = rewriter.create<mlir::LLVM::CountTrailingZerosOp>( + op.getLoc(), resTy, adaptor.getInput(), /*is_zero_poison=*/true); + + auto one = rewriter.create<mlir::LLVM::ConstantOp>(op.getLoc(), resTy, 1); + auto ctzAddOne = rewriter.create<mlir::LLVM::AddOp>(op.getLoc(), ctz, one); + + auto zeroInputTy = rewriter.create<mlir::LLVM::ConstantOp>( + op.getLoc(), adaptor.getInput().getType(), 0); + auto isZero = rewriter.create<mlir::LLVM::ICmpOp>( + op.getLoc(), + mlir::LLVM::ICmpPredicateAttr::get(rewriter.getContext(), + mlir::LLVM::ICmpPredicate::eq), + adaptor.getInput(), zeroInputTy); + + auto zero = rewriter.create<mlir::LLVM::ConstantOp>(op.getLoc(), resTy, 0); + auto res = rewriter.create<mlir::LLVM::SelectOp>(op.getLoc(), isZero, zero, + ctzAddOne); + rewriter.replaceOp(op, res); + + return mlir::LogicalResult::success(); +} + mlir::LogicalResult CIRToLLVMBitParityOpLowering::matchAndRewrite( cir::BitParityOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { @@ -2089,6 +2115,7 @@ void ConvertCIRToLLVMPass::runOnOperation() { CIRToLLVMBitClrsbOpLowering, CIRToLLVMBitClzOpLowering, CIRToLLVMBitCtzOpLowering, + CIRToLLVMBitFfsOpLowering, CIRToLLVMBitParityOpLowering, CIRToLLVMBitPopcountOpLowering, CIRToLLVMBitReverseOpLowering, diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index 2911ced..1e2094e 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -84,6 +84,16 @@ public: mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMBitFfsOpLowering + : public mlir::OpConversionPattern<cir::BitFfsOp> { +public: + using mlir::OpConversionPattern<cir::BitFfsOp>::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::BitFfsOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + class CIRToLLVMBitParityOpLowering : public mlir::OpConversionPattern<cir::BitParityOp> { public: diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index eb5b604..2c0767f 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -908,6 +908,8 @@ bool CodeGenAction::loadLinkModules(CompilerInstance &CI) { bool CodeGenAction::hasIRSupport() const { return true; } void CodeGenAction::EndSourceFileAction() { + ASTFrontendAction::EndSourceFileAction(); + // If the consumer creation failed, do nothing. if (!getCompilerInstance().hasASTConsumer()) return; @@ -932,7 +934,7 @@ CodeGenerator *CodeGenAction::getCodeGenerator() const { bool CodeGenAction::BeginSourceFileAction(CompilerInstance &CI) { if (CI.getFrontendOpts().GenReducedBMI) CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface); - return true; + return ASTFrontendAction::BeginSourceFileAction(CI); } static std::unique_ptr<raw_pwrite_stream> diff --git a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp index 2e6b4b3..980f7eb 100644 --- a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp @@ -4922,19 +4922,6 @@ Value *CodeGenFunction::EmitAArch64SMEBuiltinExpr(unsigned BuiltinID, if (Builtin->LLVMIntrinsic == 0) return nullptr; - if (BuiltinID == SME::BI__builtin_sme___arm_in_streaming_mode) { - // If we already know the streaming mode, don't bother with the intrinsic - // and emit a constant instead - const auto *FD = cast<FunctionDecl>(CurFuncDecl); - if (const auto *FPT = FD->getType()->getAs<FunctionProtoType>()) { - unsigned SMEAttrs = FPT->getAArch64SMEAttributes(); - if (!(SMEAttrs & FunctionType::SME_PStateSMCompatibleMask)) { - bool IsStreaming = SMEAttrs & FunctionType::SME_PStateSMEnabledMask; - return ConstantInt::getBool(Builder.getContext(), IsStreaming); - } - } - } - // Predicates must match the main datatype. for (Value *&Op : Ops) if (auto PredTy = dyn_cast<llvm::VectorType>(Op->getType())) diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 853f694..99de951 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -910,7 +910,7 @@ getSystemOffloadArchs(Compilation &C, Action::OffloadKind Kind) { SmallVector<std::string> GPUArchs; if (llvm::ErrorOr<std::string> Executable = - llvm::sys::findProgramByName(Program)) { + llvm::sys::findProgramByName(Program, {C.getDriver().Dir})) { llvm::SmallVector<StringRef> Args{*Executable}; if (Kind == Action::OFK_HIP) Args.push_back("--only=amdgpu"); @@ -4919,13 +4919,14 @@ Action *Driver::BuildOffloadingActions(Compilation &C, } // HIP code in device-only non-RDC mode will bundle the output if it invoked - // the linker. + // the linker or if the user explicitly requested it. bool ShouldBundleHIP = - HIPNoRDC && offloadDeviceOnly() && Args.hasFlag(options::OPT_gpu_bundle_output, - options::OPT_no_gpu_bundle_output, true) && - !llvm::any_of(OffloadActions, - [](Action *A) { return A->getType() != types::TY_Image; }); + options::OPT_no_gpu_bundle_output, false) || + (HIPNoRDC && offloadDeviceOnly() && + llvm::none_of(OffloadActions, [](Action *A) { + return A->getType() != types::TY_Image; + })); // All kinds exit now in device-only mode except for non-RDC mode HIP. if (offloadDeviceOnly() && !ShouldBundleHIP) diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 1d7dad0..496c0dc 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -191,9 +191,10 @@ static void getAArch64MultilibFlags(const Driver &D, for (const auto &ArchInfo : AArch64::ArchInfos) if (FeatureSet.contains(ArchInfo->ArchFeature)) ArchName = ArchInfo->Name; - assert(!ArchName.empty() && "at least one architecture should be found"); - MArch.insert(MArch.begin(), ("-march=" + ArchName).str()); - Result.push_back(llvm::join(MArch, "+")); + if (!ArchName.empty()) { + MArch.insert(MArch.begin(), ("-march=" + ArchName).str()); + Result.push_back(llvm::join(MArch, "+")); + } const Arg *BranchProtectionArg = Args.getLastArgNoClaim(options::OPT_mbranch_protection_EQ); diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index 6bd710e..418f9fd 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -467,3 +467,18 @@ void aarch64::setPAuthABIInTriple(const Driver &D, const ArgList &Args, break; } } + +/// Is the triple {aarch64.aarch64_be}-none-elf? +bool aarch64::isAArch64BareMetal(const llvm::Triple &Triple) { + if (Triple.getArch() != llvm::Triple::aarch64 && + Triple.getArch() != llvm::Triple::aarch64_be) + return false; + + if (Triple.getVendor() != llvm::Triple::UnknownVendor) + return false; + + if (Triple.getOS() != llvm::Triple::UnknownOS) + return false; + + return Triple.getEnvironmentName() == "elf"; +} diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.h b/clang/lib/Driver/ToolChains/Arch/AArch64.h index 2057272..2765ee8 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.h +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.h @@ -30,6 +30,7 @@ std::string getAArch64TargetCPU(const llvm::opt::ArgList &Args, void setPAuthABIInTriple(const Driver &D, const llvm::opt::ArgList &Args, llvm::Triple &triple); +bool isAArch64BareMetal(const llvm::Triple &Triple); } // end namespace aarch64 } // end namespace target diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp index 497f333..207150e 100644 --- a/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -12,6 +12,7 @@ #include "clang/Driver/CommonArgs.h" #include "clang/Driver/InputInfo.h" +#include "Arch/AArch64.h" #include "Arch/ARM.h" #include "Arch/RISCV.h" #include "clang/Driver/Compilation.h" @@ -31,21 +32,6 @@ using namespace clang::driver; using namespace clang::driver::tools; using namespace clang::driver::toolchains; -/// Is the triple {aarch64.aarch64_be}-none-elf? -static bool isAArch64BareMetal(const llvm::Triple &Triple) { - if (Triple.getArch() != llvm::Triple::aarch64 && - Triple.getArch() != llvm::Triple::aarch64_be) - return false; - - if (Triple.getVendor() != llvm::Triple::UnknownVendor) - return false; - - if (Triple.getOS() != llvm::Triple::UnknownOS) - return false; - - return Triple.getEnvironmentName() == "elf"; -} - static bool isRISCVBareMetal(const llvm::Triple &Triple) { if (!Triple.isRISCV()) return false; @@ -363,8 +349,9 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple, } bool BareMetal::handlesTarget(const llvm::Triple &Triple) { - return arm::isARMEABIBareMetal(Triple) || isAArch64BareMetal(Triple) || - isRISCVBareMetal(Triple) || isPPCBareMetal(Triple); + return arm::isARMEABIBareMetal(Triple) || + aarch64::isAArch64BareMetal(Triple) || isRISCVBareMetal(Triple) || + isPPCBareMetal(Triple); } Tool *BareMetal::buildLinker() const { diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 826e2ea..3086c14 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -547,15 +547,22 @@ const char *tools::getLDMOption(const llvm::Triple &T, const ArgList &Args) { case llvm::Triple::aarch64: if (T.isOSManagarm()) return "aarch64managarm"; + else if (aarch64::isAArch64BareMetal(T)) + return "aarch64elf"; return "aarch64linux"; case llvm::Triple::aarch64_be: + if (aarch64::isAArch64BareMetal(T)) + return "aarch64elfb"; return "aarch64linuxb"; case llvm::Triple::arm: case llvm::Triple::thumb: case llvm::Triple::armeb: - case llvm::Triple::thumbeb: - return tools::arm::isARMBigEndian(T, Args) ? "armelfb_linux_eabi" - : "armelf_linux_eabi"; + case llvm::Triple::thumbeb: { + bool IsBigEndian = tools::arm::isARMBigEndian(T, Args); + if (arm::isARMEABIBareMetal(T)) + return IsBigEndian ? "armelfb" : "armelf"; + return IsBigEndian ? "armelfb_linux_eabi" : "armelf_linux_eabi"; + } case llvm::Triple::m68k: return "m68kelf"; case llvm::Triple::ppc: diff --git a/clang/lib/Driver/ToolChains/HIPSPV.cpp b/clang/lib/Driver/ToolChains/HIPSPV.cpp index 643a67f..62bca04 100644 --- a/clang/lib/Driver/ToolChains/HIPSPV.cpp +++ b/clang/lib/Driver/ToolChains/HIPSPV.cpp @@ -69,8 +69,17 @@ void HIPSPV::Linker::constructLinkAndEmitSpirvCommand( // Link LLVM bitcode. ArgStringList LinkArgs{}; + for (auto Input : Inputs) LinkArgs.push_back(Input.getFilename()); + + // Add static device libraries using the common helper function. + // This handles unbundling archives (.a) containing bitcode bundles. + StringRef Arch = getToolChain().getTriple().getArchName(); + StringRef Target = + "generic"; // SPIR-V is generic, no specific target ID like -mcpu + tools::AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, LinkArgs, Arch, + Target, /*IsBitCodeSDL=*/true); LinkArgs.append({"-o", TempFile}); const char *LlvmLink = Args.MakeArgString(getToolChain().GetProgramPath("llvm-link")); diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index e6808f7..0637807 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -2639,32 +2639,44 @@ private: int countVariableAlignments(const SmallVectorImpl<AnnotatedLine *> &Lines) { int AlignmentDiff = 0; + for (const AnnotatedLine *Line : Lines) { AlignmentDiff += countVariableAlignments(Line->Children); - for (FormatToken *Tok = Line->First; Tok && Tok->Next; Tok = Tok->Next) { + + for (const auto *Tok = Line->getFirstNonComment(); Tok; Tok = Tok->Next) { if (Tok->isNot(TT_PointerOrReference)) continue; - // Don't treat space in `void foo() &&` or `void() &&` as evidence. - if (const auto *Prev = Tok->getPreviousNonComment()) { - if (Prev->is(tok::r_paren) && Prev->MatchingParen) { - if (const auto *Func = - Prev->MatchingParen->getPreviousNonComment()) { - if (Func->isOneOf(TT_FunctionDeclarationName, TT_StartOfName, - TT_OverloadedOperator) || - Func->isTypeName(LangOpts)) { - continue; - } - } - } + + const auto *Prev = Tok->Previous; + const bool PrecededByName = Prev && Prev->Tok.getIdentifierInfo(); + const bool SpaceBefore = Tok->hasWhitespaceBefore(); + + // e.g. `int **`, `int*&`, etc. + while (Tok->Next && Tok->Next->is(TT_PointerOrReference)) + Tok = Tok->Next; + + const auto *Next = Tok->Next; + const bool FollowedByName = Next && Next->Tok.getIdentifierInfo(); + const bool SpaceAfter = Next && Next->hasWhitespaceBefore(); + + if ((!PrecededByName && !FollowedByName) || + // e.g. `int * i` or `int*i` + (PrecededByName && FollowedByName && SpaceBefore == SpaceAfter)) { + continue; } - bool SpaceBefore = Tok->hasWhitespaceBefore(); - bool SpaceAfter = Tok->Next->hasWhitespaceBefore(); - if (SpaceBefore && !SpaceAfter) + + if ((PrecededByName && SpaceBefore) || + (FollowedByName && !SpaceAfter)) { + // Right alignment. ++AlignmentDiff; - if (!SpaceBefore && SpaceAfter) + } else if ((PrecededByName && !SpaceBefore) || + (FollowedByName && SpaceAfter)) { + // Left alignment. --AlignmentDiff; + } } } + return AlignmentDiff; } diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index dcfbd53..685a9bb 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -181,7 +181,7 @@ bool GeneratePCHAction::shouldEraseOutputFiles() { bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI) { CI.getLangOpts().CompilingPCH = true; - return true; + return ASTFrontendAction::BeginSourceFileAction(CI); } std::vector<std::unique_ptr<ASTConsumer>> diff --git a/clang/lib/Frontend/Rewrite/FrontendActions.cpp b/clang/lib/Frontend/Rewrite/FrontendActions.cpp index 84e7a4f..6c9c9d5 100644 --- a/clang/lib/Frontend/Rewrite/FrontendActions.cpp +++ b/clang/lib/Frontend/Rewrite/FrontendActions.cpp @@ -103,12 +103,13 @@ bool FixItAction::BeginSourceFileAction(CompilerInstance &CI) { } Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(), CI.getLangOpts(), FixItOpts.get())); - return true; + return ASTFrontendAction::BeginSourceFileAction(CI); } void FixItAction::EndSourceFileAction() { // Otherwise rewrite all files. Rewriter->WriteFixedFiles(); + ASTFrontendAction::EndSourceFileAction(); } bool FixItRecompile::BeginInvocation(CompilerInstance &CI) { @@ -298,7 +299,7 @@ bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) { std::make_unique<RewriteImportsListener>(CI, OutputStream)); } - return true; + return PreprocessorFrontendAction::BeginSourceFileAction(CI); } void RewriteIncludesAction::ExecuteAction() { diff --git a/clang/lib/Headers/avx10_2_512niintrin.h b/clang/lib/Headers/avx10_2_512niintrin.h index 7e614f7..9d96e36c7 100644 --- a/clang/lib/Headers/avx10_2_512niintrin.h +++ b/clang/lib/Headers/avx10_2_512niintrin.h @@ -197,7 +197,7 @@ _mm512_mask_dpwsud_epi32(__m512i __A, __mmask16 __U, __m512i __B, __m512i __C) { } static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_maskz_dpwsud_epi32( - __m512i __A, __mmask16 __U, __m512i __B, __m512i __C) { + __mmask16 __U, __m512i __A, __m512i __B, __m512i __C) { return (__m512i)__builtin_ia32_selectd_512( (__mmask16)__U, (__v16si)_mm512_dpwsud_epi32(__A, __B, __C), (__v16si)_mm512_setzero_si512()); @@ -218,7 +218,7 @@ static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_mask_dpwsuds_epi32( } static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_maskz_dpwsuds_epi32( - __m512i __A, __mmask16 __U, __m512i __B, __m512i __C) { + __mmask16 __U, __m512i __A, __m512i __B, __m512i __C) { return (__m512i)__builtin_ia32_selectd_512( (__mmask16)__U, (__v16si)_mm512_dpwsuds_epi32(__A, __B, __C), (__v16si)_mm512_setzero_si512()); @@ -239,7 +239,7 @@ _mm512_mask_dpwusd_epi32(__m512i __A, __mmask16 __U, __m512i __B, __m512i __C) { } static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_maskz_dpwusd_epi32( - __m512i __A, __mmask16 __U, __m512i __B, __m512i __C) { + __mmask16 __U, __m512i __A, __m512i __B, __m512i __C) { return (__m512i)__builtin_ia32_selectd_512( (__mmask16)__U, (__v16si)_mm512_dpwusd_epi32(__A, __B, __C), (__v16si)_mm512_setzero_si512()); @@ -260,7 +260,7 @@ static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_mask_dpwusds_epi32( } static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_maskz_dpwusds_epi32( - __m512i __A, __mmask16 __U, __m512i __B, __m512i __C) { + __mmask16 __U, __m512i __A, __m512i __B, __m512i __C) { return (__m512i)__builtin_ia32_selectd_512( (__mmask16)__U, (__v16si)_mm512_dpwusds_epi32(__A, __B, __C), (__v16si)_mm512_setzero_si512()); @@ -281,7 +281,7 @@ _mm512_mask_dpwuud_epi32(__m512i __A, __mmask16 __U, __m512i __B, __m512i __C) { } static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_maskz_dpwuud_epi32( - __m512i __A, __mmask16 __U, __m512i __B, __m512i __C) { + __mmask16 __U, __m512i __A, __m512i __B, __m512i __C) { return (__m512i)__builtin_ia32_selectd_512( (__mmask16)__U, (__v16si)_mm512_dpwuud_epi32(__A, __B, __C), (__v16si)_mm512_setzero_si512()); @@ -302,7 +302,7 @@ static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_mask_dpwuuds_epi32( } static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_maskz_dpwuuds_epi32( - __m512i __A, __mmask16 __U, __m512i __B, __m512i __C) { + __mmask16 __U, __m512i __A, __m512i __B, __m512i __C) { return (__m512i)__builtin_ia32_selectd_512( (__mmask16)__U, (__v16si)_mm512_dpwuuds_epi32(__A, __B, __C), (__v16si)_mm512_setzero_si512()); diff --git a/clang/lib/Headers/avx10_2niintrin.h b/clang/lib/Headers/avx10_2niintrin.h index 992be18..d5a66cf 100644 --- a/clang/lib/Headers/avx10_2niintrin.h +++ b/clang/lib/Headers/avx10_2niintrin.h @@ -253,7 +253,7 @@ _mm_mask_dpwsud_epi32(__m128i __A, __mmask8 __U, __m128i __B, __m128i __C) { } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_maskz_dpwsud_epi32(__m128i __A, __mmask8 __U, __m128i __B, __m128i __C) { +_mm_maskz_dpwsud_epi32(__mmask8 __U, __m128i __A, __m128i __B, __m128i __C) { return (__m128i)__builtin_ia32_selectd_128( (__mmask8)__U, (__v4si)_mm_dpwsud_epi32(__A, __B, __C), (__v4si)_mm_setzero_si128()); @@ -266,7 +266,7 @@ _mm256_mask_dpwsud_epi32(__m256i __A, __mmask8 __U, __m256i __B, __m256i __C) { } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_maskz_dpwsud_epi32(__m256i __A, __mmask8 __U, __m256i __B, __m256i __C) { +_mm256_maskz_dpwsud_epi32(__mmask8 __U, __m256i __A, __m256i __B, __m256i __C) { return (__m256i)__builtin_ia32_selectd_256( (__mmask8)__U, (__v8si)_mm256_dpwsud_epi32(__A, __B, __C), (__v8si)_mm256_setzero_si256()); @@ -279,7 +279,7 @@ _mm_mask_dpwsuds_epi32(__m128i __A, __mmask8 __U, __m128i __B, __m128i __C) { } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_maskz_dpwsuds_epi32(__m128i __A, __mmask8 __U, __m128i __B, __m128i __C) { +_mm_maskz_dpwsuds_epi32(__mmask8 __U, __m128i __A, __m128i __B, __m128i __C) { return (__m128i)__builtin_ia32_selectd_128( (__mmask8)__U, (__v4si)_mm_dpwsuds_epi32(__A, __B, __C), (__v4si)_mm_setzero_si128()); @@ -292,7 +292,7 @@ _mm256_mask_dpwsuds_epi32(__m256i __A, __mmask8 __U, __m256i __B, __m256i __C) { } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_maskz_dpwsuds_epi32( - __m256i __A, __mmask8 __U, __m256i __B, __m256i __C) { + __mmask8 __U, __m256i __A, __m256i __B, __m256i __C) { return (__m256i)__builtin_ia32_selectd_256( (__mmask8)__U, (__v8si)_mm256_dpwsuds_epi32(__A, __B, __C), (__v8si)_mm256_setzero_si256()); @@ -305,7 +305,7 @@ _mm_mask_dpwusd_epi32(__m128i __A, __mmask8 __U, __m128i __B, __m128i __C) { } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_maskz_dpwusd_epi32(__m128i __A, __mmask8 __U, __m128i __B, __m128i __C) { +_mm_maskz_dpwusd_epi32(__mmask8 __U, __m128i __A, __m128i __B, __m128i __C) { return (__m128i)__builtin_ia32_selectd_128( (__mmask8)__U, (__v4si)_mm_dpwusd_epi32(__A, __B, __C), (__v4si)_mm_setzero_si128()); @@ -318,7 +318,7 @@ _mm256_mask_dpwusd_epi32(__m256i __A, __mmask8 __U, __m256i __B, __m256i __C) { } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_maskz_dpwusd_epi32(__m256i __A, __mmask8 __U, __m256i __B, __m256i __C) { +_mm256_maskz_dpwusd_epi32(__mmask8 __U, __m256i __A, __m256i __B, __m256i __C) { return (__m256i)__builtin_ia32_selectd_256( (__mmask8)__U, (__v8si)_mm256_dpwusd_epi32(__A, __B, __C), (__v8si)_mm256_setzero_si256()); @@ -331,7 +331,7 @@ _mm_mask_dpwusds_epi32(__m128i __A, __mmask8 __U, __m128i __B, __m128i __C) { } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_maskz_dpwusds_epi32(__m128i __A, __mmask8 __U, __m128i __B, __m128i __C) { +_mm_maskz_dpwusds_epi32(__mmask8 __U, __m128i __A, __m128i __B, __m128i __C) { return (__m128i)__builtin_ia32_selectd_128( (__mmask8)__U, (__v4si)_mm_dpwusds_epi32(__A, __B, __C), (__v4si)_mm_setzero_si128()); @@ -344,7 +344,7 @@ _mm256_mask_dpwusds_epi32(__m256i __A, __mmask8 __U, __m256i __B, __m256i __C) { } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_maskz_dpwusds_epi32( - __m256i __A, __mmask8 __U, __m256i __B, __m256i __C) { + __mmask8 __U, __m256i __A, __m256i __B, __m256i __C) { return (__m256i)__builtin_ia32_selectd_256( (__mmask8)__U, (__v8si)_mm256_dpwusds_epi32(__A, __B, __C), (__v8si)_mm256_setzero_si256()); @@ -357,7 +357,7 @@ _mm_mask_dpwuud_epi32(__m128i __A, __mmask8 __U, __m128i __B, __m128i __C) { } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_maskz_dpwuud_epi32(__m128i __A, __mmask8 __U, __m128i __B, __m128i __C) { +_mm_maskz_dpwuud_epi32(__mmask8 __U, __m128i __A, __m128i __B, __m128i __C) { return (__m128i)__builtin_ia32_selectd_128( (__mmask8)__U, (__v4si)_mm_dpwuud_epi32(__A, __B, __C), (__v4si)_mm_setzero_si128()); @@ -370,7 +370,7 @@ _mm256_mask_dpwuud_epi32(__m256i __A, __mmask8 __U, __m256i __B, __m256i __C) { } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_maskz_dpwuud_epi32(__m256i __A, __mmask8 __U, __m256i __B, __m256i __C) { +_mm256_maskz_dpwuud_epi32(__mmask8 __U, __m256i __A, __m256i __B, __m256i __C) { return (__m256i)__builtin_ia32_selectd_256( (__mmask8)__U, (__v8si)_mm256_dpwuud_epi32(__A, __B, __C), (__v8si)_mm256_setzero_si256()); @@ -383,7 +383,7 @@ _mm_mask_dpwuuds_epi32(__m128i __A, __mmask8 __U, __m128i __B, __m128i __C) { } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_maskz_dpwuuds_epi32(__m128i __A, __mmask8 __U, __m128i __B, __m128i __C) { +_mm_maskz_dpwuuds_epi32(__mmask8 __U, __m128i __A, __m128i __B, __m128i __C) { return (__m128i)__builtin_ia32_selectd_128( (__mmask8)__U, (__v4si)_mm_dpwuuds_epi32(__A, __B, __C), (__v4si)_mm_setzero_si128()); @@ -396,7 +396,7 @@ _mm256_mask_dpwuuds_epi32(__m256i __A, __mmask8 __U, __m256i __B, __m256i __C) { } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_maskz_dpwuuds_epi32( - __m256i __A, __mmask8 __U, __m256i __B, __m256i __C) { + __mmask8 __U, __m256i __A, __m256i __B, __m256i __C) { return (__m256i)__builtin_ia32_selectd_256( (__mmask8)__U, (__v8si)_mm256_dpwuuds_epi32(__A, __B, __C), (__v8si)_mm256_setzero_si256()); diff --git a/clang/lib/Headers/opencl-c-base.h b/clang/lib/Headers/opencl-c-base.h index 2b7f504..6206a34 100644 --- a/clang/lib/Headers/opencl-c-base.h +++ b/clang/lib/Headers/opencl-c-base.h @@ -697,7 +697,16 @@ template <typename _Tp> struct __remove_address_space<__constant _Tp> { #if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2) // OpenCL v1.2 s6.12.13, v2.0 s6.13.13 - printf -int printf(__constant const char* st, ...) __attribute__((format(printf, 1, 2))); +#ifdef __OPENCL_CPP_VERSION__ +#define CLINKAGE extern "C" +#else +#define CLINKAGE +#endif + +CLINKAGE int printf(__constant const char *st, ...) + __attribute__((format(printf, 1, 2))); + +#undef CLINKAGE #endif #ifdef cl_intel_device_side_avc_motion_estimation diff --git a/clang/lib/Headers/opencl-c.h b/clang/lib/Headers/opencl-c.h index e1e0fde..f65b4b3 100644 --- a/clang/lib/Headers/opencl-c.h +++ b/clang/lib/Headers/opencl-c.h @@ -18410,6 +18410,22 @@ intel_sub_group_avc_mce_convert_to_sic_result( #pragma OPENCL EXTENSION cl_intel_device_side_avc_motion_estimation : end #endif // cl_intel_device_side_avc_motion_estimation +#if defined(cl_intel_bfloat16_conversions) +ushort __ovld intel_convert_bfloat16_as_ushort(float source); +ushort2 __ovld intel_convert_bfloat162_as_ushort2(float2 source); +ushort3 __ovld intel_convert_bfloat163_as_ushort3(float3 source); +ushort4 __ovld intel_convert_bfloat164_as_ushort4(float4 source); +ushort8 __ovld intel_convert_bfloat168_as_ushort8(float8 source); +ushort16 __ovld intel_convert_bfloat1616_as_ushort16(float16 source); + +float __ovld intel_convert_as_bfloat16_float(ushort source); +float2 __ovld intel_convert_as_bfloat162_float2(ushort2 source); +float3 __ovld intel_convert_as_bfloat163_float3(ushort3 source); +float4 __ovld intel_convert_as_bfloat164_float4(ushort4 source); +float8 __ovld intel_convert_as_bfloat168_float8(ushort8 source); +float16 __ovld intel_convert_as_bfloat1616_float16(ushort16 source); +#endif // cl_intel_bfloat16_conversions + #ifdef cl_amd_media_ops uint __ovld amd_bitalign(uint, uint, uint); uint2 __ovld amd_bitalign(uint2, uint2, uint2); diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 890567c..6f12ac8 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1760,7 +1760,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Tok, *this, diag::err_feature_check_malformed); if (!II) return false; - else if (II->getBuiltinID() != 0) { + unsigned BuiltinID = II->getBuiltinID(); + if (BuiltinID != 0) { switch (II->getBuiltinID()) { case Builtin::BI__builtin_cpu_is: return getTargetInfo().supportsCpuIs(); @@ -1774,8 +1775,11 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // usual allocation and deallocation functions. Required by libc++ return 201802; default: + // __has_builtin should return false for aux builtins. + if (getBuiltinInfo().isAuxBuiltinID(BuiltinID)) + return false; return Builtin::evaluateRequiredTargetFeatures( - getBuiltinInfo().getRequiredFeatures(II->getBuiltinID()), + getBuiltinInfo().getRequiredFeatures(BuiltinID), getTargetInfo().getTargetOpts().FeatureMap); } return true; diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 56608e9..d50eeff 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1616,6 +1616,8 @@ void Sema::ActOnEndOfTranslationUnit() { if (!PP.isIncrementalProcessingEnabled()) TUScope = nullptr; + + checkExposure(Context.getTranslationUnitDecl()); } diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp index 8e27fab..e09c352 100644 --- a/clang/lib/Sema/SemaARM.cpp +++ b/clang/lib/Sema/SemaARM.cpp @@ -846,9 +846,9 @@ bool SemaARM::CheckARMCoprocessorImmediate(const TargetInfo &TI, return false; } -bool SemaARM::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, - CallExpr *TheCall, - unsigned MaxWidth) { +bool SemaARM::CheckARMBuiltinExclusiveCall(const TargetInfo &TI, + unsigned BuiltinID, + CallExpr *TheCall) { assert((BuiltinID == ARM::BI__builtin_arm_ldrex || BuiltinID == ARM::BI__builtin_arm_ldaex || BuiltinID == ARM::BI__builtin_arm_strex || @@ -923,12 +923,56 @@ bool SemaARM::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, return true; } - // But ARM doesn't have instructions to deal with 128-bit versions. - if (Context.getTypeSize(ValType) > MaxWidth) { - assert(MaxWidth == 64 && "Diagnostic unexpectedly inaccurate"); - Diag(DRE->getBeginLoc(), diag::err_atomic_exclusive_builtin_pointer_size) - << PointerArg->getType() << PointerArg->getSourceRange(); - return true; + // Check whether the size of the type can be handled atomically on this + // target. + if (!TI.getTriple().isAArch64()) { + unsigned Mask = TI.getARMLDREXMask(); + unsigned Bits = Context.getTypeSize(ValType); + bool Supported = + (llvm::isPowerOf2_64(Bits)) && Bits >= 8 && (Mask & (Bits / 8)); + + if (!Supported) { + // Emit a diagnostic saying that this size isn't available. If _no_ size + // of exclusive access is supported on this target, we emit a diagnostic + // with special wording for that case, but otherwise, we emit + // err_atomic_exclusive_builtin_pointer_size and loop over `Mask` to + // control what subset of sizes it lists as legal. + if (Mask) { + auto D = Diag(DRE->getBeginLoc(), + diag::err_atomic_exclusive_builtin_pointer_size) + << PointerArg->getType(); + bool Started = false; + for (unsigned Size = 1; Size <= 8; Size <<= 1) { + // For each of the sizes 1,2,4,8, pass two integers into the + // diagnostic. The first selects a separator from the previous + // number: 0 for no separator at all, 1 for a comma, 2 for " or " + // which appears before the final number in a list of more than one. + // The second integer just indicates whether we print this size in + // the message at all. + if (!(Mask & Size)) { + // This size isn't one of the supported ones, so emit no separator + // text and don't print the size itself. + D << 0 << 0; + } else { + // This size is supported, so print it, and an appropriate + // separator. + Mask &= ~Size; + if (!Started) + D << 0; // No separator if this is the first size we've printed + else if (Mask) + D << 1; // "," if there's still another size to come + else + D << 2; // " or " if the size we're about to print is the last + D << 1; // print the size itself + Started = true; + } + } + } else { + Diag(DRE->getBeginLoc(), + diag::err_atomic_exclusive_builtin_pointer_size_none) + << PointerArg->getSourceRange(); + } + } } switch (ValType.getObjCLifetime()) { @@ -972,7 +1016,7 @@ bool SemaARM::CheckARMBuiltinFunctionCall(const TargetInfo &TI, BuiltinID == ARM::BI__builtin_arm_ldaex || BuiltinID == ARM::BI__builtin_arm_strex || BuiltinID == ARM::BI__builtin_arm_stlex) { - return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 64); + return CheckARMBuiltinExclusiveCall(TI, BuiltinID, TheCall); } if (BuiltinID == ARM::BI__builtin_arm_prefetch) { @@ -1053,7 +1097,7 @@ bool SemaARM::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, BuiltinID == AArch64::BI__builtin_arm_ldaex || BuiltinID == AArch64::BI__builtin_arm_strex || BuiltinID == AArch64::BI__builtin_arm_stlex) { - return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 128); + return CheckARMBuiltinExclusiveCall(TI, BuiltinID, TheCall); } if (BuiltinID == AArch64::BI__builtin_arm_prefetch) { diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index a4e8de4..16b18bc 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4805,10 +4805,10 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI, static void handleNonStringAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // This only applies to fields and variable declarations which have an array - // type. + // type or pointer type, with character elements. QualType QT = cast<ValueDecl>(D)->getType(); - if (!QT->isArrayType() || - !QT->getBaseElementTypeUnsafe()->isAnyCharacterType()) { + if ((!QT->isArrayType() && !QT->isPointerType()) || + !QT->getPointeeOrArrayElementType()->isAnyCharacterType()) { S.Diag(D->getBeginLoc(), diag::warn_attribute_non_character_array) << AL << AL.isRegularKeywordAttribute() << QT << AL.getRange(); return; diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index 7c982bc..98ebd70 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -13,6 +13,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTMutationListener.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/ParsedAttr.h" @@ -485,6 +486,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, // implementation unit importing its interface). Make this module visible // and return the import decl to be added to the current TU. if (Interface) { + HadImportedNamedModules = true; makeTransitiveImportsVisible(getASTContext(), VisibleModules, Interface, Mod, ModuleLoc, @@ -728,6 +730,8 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, getCurrentModule()->Imports.insert(Mod); } + HadImportedNamedModules = true; + return Import; } @@ -1102,3 +1106,471 @@ bool Sema::isCurrentModulePurview() const { return false; } } + +//===----------------------------------------------------------------------===// +// Checking Exposure in modules // +//===----------------------------------------------------------------------===// + +namespace { +class ExposureChecker { +public: + ExposureChecker(Sema &S) : SemaRef(S) {} + + bool checkExposure(const VarDecl *D, bool Diag); + bool checkExposure(const CXXRecordDecl *D, bool Diag); + bool checkExposure(const Stmt *S, bool Diag); + bool checkExposure(const FunctionDecl *D, bool Diag); + bool checkExposure(const NamedDecl *D, bool Diag); + void checkExposureInContext(const DeclContext *DC); + bool isExposureCandidate(const NamedDecl *D); + + bool isTULocal(QualType Ty); + bool isTULocal(const NamedDecl *ND); + bool isTULocal(const Expr *E); + + Sema &SemaRef; + +private: + llvm::DenseSet<const NamedDecl *> ExposureSet; + llvm::DenseSet<const NamedDecl *> KnownNonExposureSet; +}; + +bool ExposureChecker::isTULocal(QualType Ty) { + // [basic.link]p15: + // An entity is TU-local if it is + // - a type, type alias, namespace, namespace alias, function, variable, or + // template that + // -- has internal linkage, or + return Ty->getLinkage() == Linkage::Internal; + + // TODO: + // [basic.link]p15.2: + // a type with no name that is defined outside a class-specifier, function + // body, or initializer or is introduced by a defining-type-specifier that + // is used to declare only TU-local entities, +} + +bool ExposureChecker::isTULocal(const NamedDecl *D) { + if (!D) + return false; + + // [basic.link]p15: + // An entity is TU-local if it is + // - a type, type alias, namespace, namespace alias, function, variable, or + // template that + // -- has internal linkage, or + if (D->getLinkageInternal() == Linkage::Internal) + return true; + + if (D->isInAnonymousNamespace()) + return true; + + // [basic.link]p15.1.2: + // does not have a name with linkage and is declared, or introduced by a + // lambda-expression, within the definition of a TU-local entity, + if (D->getLinkageInternal() == Linkage::None) + if (auto *ND = dyn_cast<NamedDecl>(D->getDeclContext()); + ND && isTULocal(ND)) + return true; + + // [basic.link]p15.3, p15.4: + // - a specialization of a TU-local template, + // - a specialization of a template with any TU-local template argument, or + ArrayRef<TemplateArgument> TemplateArgs; + NamedDecl *PrimaryTemplate = nullptr; + if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + TemplateArgs = CTSD->getTemplateArgs().asArray(); + PrimaryTemplate = CTSD->getSpecializedTemplate(); + if (isTULocal(PrimaryTemplate)) + return true; + } else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) { + TemplateArgs = VTSD->getTemplateArgs().asArray(); + PrimaryTemplate = VTSD->getSpecializedTemplate(); + if (isTULocal(PrimaryTemplate)) + return true; + } else if (auto *FD = dyn_cast<FunctionDecl>(D)) { + if (auto *TAList = FD->getTemplateSpecializationArgs()) + TemplateArgs = TAList->asArray(); + + PrimaryTemplate = FD->getPrimaryTemplate(); + if (isTULocal(PrimaryTemplate)) + return true; + } + + if (!PrimaryTemplate) + // Following off, we only check for specializations. + return false; + + if (KnownNonExposureSet.count(D)) + return false; + + for (auto &TA : TemplateArgs) { + switch (TA.getKind()) { + case TemplateArgument::Type: + if (isTULocal(TA.getAsType())) + return true; + break; + case TemplateArgument::Declaration: + if (isTULocal(TA.getAsDecl())) + return true; + break; + default: + break; + } + } + + // [basic.link]p15.5 + // - a specialization of a template whose (possibly instantiated) declaration + // is an exposure. + if (checkExposure(PrimaryTemplate, /*Diag=*/false)) + return true; + + // Avoid calling checkExposure again since it is expensive. + KnownNonExposureSet.insert(D); + return false; +} + +bool ExposureChecker::isTULocal(const Expr *E) { + if (!E) + return false; + + // [basic.link]p16: + // A value or object is TU-local if either + // - it is of TU-local type, + if (isTULocal(E->getType())) + return true; + + E = E->IgnoreParenImpCasts(); + // [basic.link]p16.2: + // - it is, or is a pointer to, a TU-local function or the object associated + // with a TU-local variable, + // - it is an object of class or array type and any of its subobjects or any + // of the objects or functions to which its non-static data members of + // reference type refer is TU-local and is usable in constant expressions, or + // FIXME: But how can we know the value of pointers or arrays at compile time? + if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) { + if (auto *FD = dyn_cast_or_null<FunctionDecl>(DRE->getFoundDecl())) + return isTULocal(FD); + else if (auto *VD = dyn_cast_or_null<VarDecl>(DRE->getFoundDecl())) + return isTULocal(VD); + else if (auto *RD = dyn_cast_or_null<CXXRecordDecl>(DRE->getFoundDecl())) + return isTULocal(RD); + } + + // TODO: + // [basic.link]p16.4: + // it is a reflection value that represents... + + return false; +} + +bool ExposureChecker::isExposureCandidate(const NamedDecl *D) { + if (!D) + return false; + + // [basic.link]p17: + // If a (possibly instantiated) declaration of, or a deduction guide for, + // a non-TU-local entity in a module interface unit + // (outside the private-module-fragment, if any) or + // module partition is an exposure, the program is ill-formed. + Module *M = D->getOwningModule(); + if (!M || !M->isInterfaceOrPartition()) + return false; + + if (D->isImplicit()) + return false; + + // [basic.link]p14: + // A declaration is an exposure if it either names a TU-local entity + // (defined below), ignoring: + // ... + // - friend declarations in a class definition + if (D->getFriendObjectKind() && + isa<CXXRecordDecl>(D->getLexicalDeclContext())) + return false; + + return true; +} + +bool ExposureChecker::checkExposure(const NamedDecl *D, bool Diag) { + if (!isExposureCandidate(D)) + return false; + + if (auto *FD = dyn_cast<FunctionDecl>(D)) + return checkExposure(FD, Diag); + if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D)) + return checkExposure(FTD->getTemplatedDecl(), Diag); + + if (auto *VD = dyn_cast<VarDecl>(D)) + return checkExposure(VD, Diag); + if (auto *VTD = dyn_cast<VarTemplateDecl>(D)) + return checkExposure(VTD->getTemplatedDecl(), Diag); + + if (auto *RD = dyn_cast<CXXRecordDecl>(D)) + return checkExposure(RD, Diag); + + if (auto *CTD = dyn_cast<ClassTemplateDecl>(D)) + return checkExposure(CTD->getTemplatedDecl(), Diag); + + return false; +} + +bool ExposureChecker::checkExposure(const FunctionDecl *FD, bool Diag) { + bool IsExposure = false; + if (isTULocal(FD->getReturnType())) { + IsExposure = true; + if (Diag) + SemaRef.Diag(FD->getReturnTypeSourceRange().getBegin(), + diag::warn_exposure) + << FD->getReturnType(); + } + + for (ParmVarDecl *Parms : FD->parameters()) + if (isTULocal(Parms->getType())) { + IsExposure = true; + if (Diag) + SemaRef.Diag(Parms->getLocation(), diag::warn_exposure) + << Parms->getType(); + } + + bool IsImplicitInstantiation = + FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation; + + // [basic.link]p14: + // A declaration is an exposure if it either names a TU-local entity + // (defined below), ignoring: + // - the function-body for a non-inline function or function template + // (but not the deduced return + // type for a (possibly instantiated) definition of a function with a + // declared return type that uses a placeholder type + // ([dcl.spec.auto])), + Diag &= + (FD->isInlined() || IsImplicitInstantiation) && !FD->isDependentContext(); + + IsExposure |= checkExposure(FD->getBody(), Diag); + if (IsExposure) + ExposureSet.insert(FD); + + return IsExposure; +} + +bool ExposureChecker::checkExposure(const VarDecl *VD, bool Diag) { + bool IsExposure = false; + // [basic.link]p14: + // A declaration is an exposure if it either names a TU-local entity (defined + // below), ignoring: + // ... + // or defines a constexpr variable initialized to a TU-local value (defined + // below). + if (VD->isConstexpr() && isTULocal(VD->getInit())) { + IsExposure = true; + if (Diag) + SemaRef.Diag(VD->getInit()->getExprLoc(), diag::warn_exposure) + << VD->getInit(); + } + + if (isTULocal(VD->getType())) { + IsExposure = true; + if (Diag) + SemaRef.Diag(VD->getLocation(), diag::warn_exposure) << VD->getType(); + } + + // [basic.link]p14: + // ..., ignoring: + // - the initializer for a variable or variable template (but not the + // variable's type), + // + // Note: although the spec says to ignore the initializer for all variable, + // for the code we generated now for inline variables, it is dangerous if the + // initializer of an inline variable is TULocal. + Diag &= !VD->getDeclContext()->isDependentContext() && VD->isInline(); + IsExposure |= checkExposure(VD->getInit(), Diag); + if (IsExposure) + ExposureSet.insert(VD); + + return IsExposure; +} + +bool ExposureChecker::checkExposure(const CXXRecordDecl *RD, bool Diag) { + if (!RD->hasDefinition()) + return false; + + bool IsExposure = false; + for (CXXMethodDecl *Method : RD->methods()) + IsExposure |= checkExposure(Method, Diag); + + for (FieldDecl *FD : RD->fields()) { + if (isTULocal(FD->getType())) { + IsExposure = true; + if (Diag) + SemaRef.Diag(FD->getLocation(), diag::warn_exposure) << FD->getType(); + } + } + + for (const CXXBaseSpecifier &Base : RD->bases()) { + if (isTULocal(Base.getType())) { + IsExposure = true; + if (Diag) + SemaRef.Diag(Base.getBaseTypeLoc(), diag::warn_exposure) + << Base.getType(); + } + } + + if (IsExposure) + ExposureSet.insert(RD); + + return IsExposure; +} + +template <typename CallbackTy> +class ReferenceTULocalChecker + : public clang::RecursiveASTVisitor<ReferenceTULocalChecker<CallbackTy>> { +public: + ReferenceTULocalChecker(ExposureChecker &C, CallbackTy &&Callback) + : Checker(C), Callback(std::move(Callback)) {} + + bool VisitDeclRefExpr(DeclRefExpr *DRE) { + ValueDecl *Referenced = DRE->getDecl(); + if (!Referenced) + return true; + + if (!Checker.isTULocal(Referenced)) + // We don't care if the referenced declaration is not TU-local. + return true; + + Qualifiers Qual = DRE->getType().getQualifiers(); + // [basic.link]p14: + // A declaration is an exposure if it either names a TU-local entity + // (defined below), ignoring: + // ... + // - any reference to a non-volatile const object ... + if (Qual.hasConst() && !Qual.hasVolatile()) + return true; + + // [basic.link]p14: + // ..., ignoring: + // ... + // (p14.4) - ... or reference with internal or no linkage initialized with + // a constant expression that is not an odr-use + ASTContext &Context = Referenced->getASTContext(); + Linkage L = Referenced->getLinkageInternal(); + if (DRE->isNonOdrUse() && (L == Linkage::Internal || L == Linkage::None)) + if (auto *VD = dyn_cast<VarDecl>(Referenced); + VD && VD->getInit() && !VD->getInit()->isValueDependent() && + VD->getInit()->isConstantInitializer(Context, /*IsForRef=*/false)) + return true; + + Callback(DRE, Referenced); + return true; + } + + ExposureChecker &Checker; + CallbackTy Callback; +}; + +template <typename CallbackTy> +ReferenceTULocalChecker(ExposureChecker &, CallbackTy &&) + -> ReferenceTULocalChecker<CallbackTy>; + +bool ExposureChecker::checkExposure(const Stmt *S, bool Diag) { + if (!S) + return false; + + bool HasReferencedTULocals = false; + ReferenceTULocalChecker Checker( + *this, [this, &HasReferencedTULocals, Diag](DeclRefExpr *DRE, + ValueDecl *Referenced) { + if (Diag) { + SemaRef.Diag(DRE->getExprLoc(), diag::warn_exposure) << Referenced; + } + HasReferencedTULocals = true; + }); + Checker.TraverseStmt(const_cast<Stmt *>(S)); + return HasReferencedTULocals; +} + +void ExposureChecker::checkExposureInContext(const DeclContext *DC) { + for (auto *TopD : DC->noload_decls()) { + auto *TopND = dyn_cast<NamedDecl>(TopD); + if (!TopND) + continue; + + if (auto *Namespace = dyn_cast<NamespaceDecl>(TopND)) { + checkExposureInContext(Namespace); + continue; + } + + // [basic.link]p17: + // If a (possibly instantiated) declaration of, or a deduction guide for, + // a non-TU-local entity in a module interface unit + // (outside the private-module-fragment, if any) or + // module partition is an exposure, the program is ill-formed. + if (!TopND->isFromASTFile() && isExposureCandidate(TopND) && + !isTULocal(TopND)) + checkExposure(TopND, /*Diag=*/true); + } +} + +} // namespace + +void Sema::checkExposure(const TranslationUnitDecl *TU) { + if (!TU) + return; + + ExposureChecker Checker(*this); + + Module *M = TU->getOwningModule(); + if (M && M->isInterfaceOrPartition()) + Checker.checkExposureInContext(TU); + + // [basic.link]p18: + // If a declaration that appears in one translation unit names a TU-local + // entity declared in another translation unit that is not a header unit, + // the program is ill-formed. + for (auto FDAndInstantiationLocPair : PendingCheckReferenceForTULocal) { + FunctionDecl *FD = FDAndInstantiationLocPair.first; + SourceLocation PointOfInstantiation = FDAndInstantiationLocPair.second; + + if (!FD->hasBody()) + continue; + + ReferenceTULocalChecker(Checker, [&, this](DeclRefExpr *DRE, + ValueDecl *Referenced) { + // A "defect" in current implementation. Now an implicit instantiation of + // a template, the instantiation is considered to be in the same module + // unit as the template instead of the module unit where the instantiation + // happens. + // + // See test/Modules/Exposre-2.cppm for example. + if (!Referenced->isFromASTFile()) + return; + + if (!Referenced->isInAnotherModuleUnit()) + return; + + // This is not standard conforming. But given there are too many static + // (inline) functions in headers in existing code, it is more user + // friendly to ignore them temporarily now. maybe we can have another flag + // for this. + if (Referenced->getOwningModule()->isExplicitGlobalModule() && + isa<FunctionDecl>(Referenced)) + return; + + Diag(PointOfInstantiation, + diag::warn_reference_tu_local_entity_in_other_tu) + << FD << Referenced + << Referenced->getOwningModule()->getTopLevelModuleName(); + }).TraverseStmt(FD->getBody()); + } +} + +void Sema::checkReferenceToTULocalFromOtherTU( + FunctionDecl *FD, SourceLocation PointOfInstantiation) { + // Checking if a declaration have any reference to TU-local entities in other + // TU is expensive. Try to avoid it as much as possible. + if (!FD || !HadImportedNamedModules) + return; + + PendingCheckReferenceForTULocal.push_back( + std::make_pair(FD, PointOfInstantiation)); +} diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 5dd5b49..76e189d 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -8042,8 +8042,8 @@ static void AddTemplateOverloadCandidateImmediately( Candidate.IgnoreObjectArgument = isa<CXXMethodDecl>(Candidate.Function) && - cast<CXXMethodDecl>(Candidate.Function) - ->isImplicitObjectMemberFunction() && + !cast<CXXMethodDecl>(Candidate.Function) + ->isExplicitObjectMemberFunction() && !isa<CXXConstructorDecl>(Candidate.Function); Candidate.ExplicitCallArguments = Args.size(); diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index f85826a..3f89843 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -295,8 +295,7 @@ void DiagnoseUnused(Sema &S, const Expr *E, std::optional<unsigned> DiagID) { return; auto [OffendingDecl, A] = CE->getUnusedResultAttr(S.Context); - if (DiagnoseNoDiscard(S, OffendingDecl, - cast_or_null<WarnUnusedResultAttr>(A), Loc, R1, R2, + if (DiagnoseNoDiscard(S, OffendingDecl, A, Loc, R1, R2, /*isCtor=*/false)) return; @@ -344,13 +343,11 @@ void DiagnoseUnused(Sema &S, const Expr *E, std::optional<unsigned> DiagID) { S.Diag(Loc, diag::err_arc_unused_init_message) << R1; return; } - const ObjCMethodDecl *MD = ME->getMethodDecl(); - if (MD) { - if (DiagnoseNoDiscard(S, nullptr, MD->getAttr<WarnUnusedResultAttr>(), - Loc, R1, R2, - /*isCtor=*/false)) - return; - } + + auto [OffendingDecl, A] = ME->getUnusedResultAttr(S.Context); + if (DiagnoseNoDiscard(S, OffendingDecl, A, Loc, R1, R2, + /*isCtor=*/false)) + return; } else if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) { const Expr *Source = POE->getSyntacticForm(); // Handle the actually selected call of an OpenMP specialized call. diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 857d46a..77aa716 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -795,6 +795,10 @@ ExprResult Sema::BuildCXXAssumeExpr(Expr *Assumption, if (Res.isInvalid()) return ExprError(); + Res = ActOnFinishFullExpr(Res.get(), /*DiscardedValue=*/false); + if (Res.isInvalid()) + return ExprError(); + Assumption = Res.get(); if (Assumption->HasSideEffects(Context)) Diag(Assumption->getBeginLoc(), diag::warn_assume_side_effects) diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 20bac0e..d84d0ca1 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2270,11 +2270,6 @@ TemplateInstantiator::TransformCXXAssumeAttr(const CXXAssumeAttr *AA) { if (!Res.isUsable()) return AA; - Res = getSema().ActOnFinishFullExpr(Res.get(), - /*DiscardedValue=*/false); - if (!Res.isUsable()) - return AA; - if (!(Res.get()->getDependence() & ExprDependence::TypeValueInstantiation)) { Res = getSema().BuildCXXAssumeExpr(Res.get(), AA->getAttrName(), AA->getRange()); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index e2c3cdc..233bb65 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -5853,6 +5853,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // context seems wrong. Investigate more. ActOnFinishFunctionBody(Function, Body.get(), /*IsInstantiation=*/true); + checkReferenceToTULocalFromOtherTU(Function, PointOfInstantiation); + PerformDependentDiagnostics(PatternDecl, TemplateArgs); if (auto *Listener = getASTMutationListener()) diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 10aedb6..f896f9f1 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -8488,6 +8488,7 @@ bool ASTReader::LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups, bool ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) { assert(D); + CompleteRedeclChain(D); bool NewSpecsFound = LoadExternalSpecializationsImpl(PartialSpecializationsLookups, D); if (OnlyPartial) diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index d7eea7e..152129e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -25,18 +25,22 @@ using namespace clang; using namespace ento; namespace { + +class DerefBugType : public BugType { + StringRef ArrayMsg, FieldMsg; + +public: + DerefBugType(CheckerFrontend *FE, StringRef Desc, const char *AMsg, + const char *FMsg = nullptr) + : BugType(FE, Desc), ArrayMsg(AMsg), FieldMsg(FMsg ? FMsg : AMsg) {} + StringRef getArrayMsg() const { return ArrayMsg; } + StringRef getFieldMsg() const { return FieldMsg; } +}; + class DereferenceChecker - : public Checker< check::Location, - check::Bind, - EventDispatcher<ImplicitNullDerefEvent> > { - enum DerefKind { - NullPointer, - UndefinedPointerValue, - AddressOfLabel, - FixedAddress, - }; - - void reportBug(DerefKind K, ProgramStateRef State, const Stmt *S, + : public CheckerFamily<check::Location, check::Bind, + EventDispatcher<ImplicitNullDerefEvent>> { + void reportBug(const DerefBugType &BT, ProgramStateRef State, const Stmt *S, CheckerContext &C) const; bool suppressReport(CheckerContext &C, const Expr *E) const; @@ -52,13 +56,23 @@ public: const LocationContext *LCtx, bool loadedFrom = false); - bool CheckNullDereference = false; - bool CheckFixedDereference = false; - - std::unique_ptr<BugType> BT_Null; - std::unique_ptr<BugType> BT_Undef; - std::unique_ptr<BugType> BT_Label; - std::unique_ptr<BugType> BT_FixedAddress; + CheckerFrontend NullDerefChecker, FixedDerefChecker; + const DerefBugType NullBug{&NullDerefChecker, "Dereference of null pointer", + "a null pointer dereference", + "a dereference of a null pointer"}; + const DerefBugType UndefBug{&NullDerefChecker, + "Dereference of undefined pointer value", + "an undefined pointer dereference", + "a dereference of an undefined pointer value"}; + const DerefBugType LabelBug{&NullDerefChecker, + "Dereference of the address of a label", + "an undefined pointer dereference", + "a dereference of an address of a label"}; + const DerefBugType FixedAddressBug{&FixedDerefChecker, + "Dereference of a fixed address", + "a dereference of a fixed address"}; + + StringRef getDebugTag() const override { return "DereferenceChecker"; } }; } // end anonymous namespace @@ -158,115 +172,87 @@ static bool isDeclRefExprToReference(const Expr *E) { return false; } -void DereferenceChecker::reportBug(DerefKind K, ProgramStateRef State, - const Stmt *S, CheckerContext &C) const { - const BugType *BT = nullptr; - llvm::StringRef DerefStr1; - llvm::StringRef DerefStr2; - switch (K) { - case DerefKind::NullPointer: - if (!CheckNullDereference) { - C.addSink(); - return; - } - BT = BT_Null.get(); - DerefStr1 = " results in a null pointer dereference"; - DerefStr2 = " results in a dereference of a null pointer"; - break; - case DerefKind::UndefinedPointerValue: - if (!CheckNullDereference) { - C.addSink(); +void DereferenceChecker::reportBug(const DerefBugType &BT, + ProgramStateRef State, const Stmt *S, + CheckerContext &C) const { + if (&BT == &FixedAddressBug) { + if (!FixedDerefChecker.isEnabled()) + // Deliberately don't add a sink node if check is disabled. + // This situation may be valid in special cases. return; - } - BT = BT_Undef.get(); - DerefStr1 = " results in an undefined pointer dereference"; - DerefStr2 = " results in a dereference of an undefined pointer value"; - break; - case DerefKind::AddressOfLabel: - if (!CheckNullDereference) { + } else { + if (!NullDerefChecker.isEnabled()) { C.addSink(); return; } - BT = BT_Label.get(); - DerefStr1 = " results in an undefined pointer dereference"; - DerefStr2 = " results in a dereference of an address of a label"; - break; - case DerefKind::FixedAddress: - // Deliberately don't add a sink node if check is disabled. - // This situation may be valid in special cases. - if (!CheckFixedDereference) - return; - - BT = BT_FixedAddress.get(); - DerefStr1 = " results in a dereference of a fixed address"; - DerefStr2 = " results in a dereference of a fixed address"; - break; - }; + } // Generate an error node. ExplodedNode *N = C.generateErrorNode(State); if (!N) return; - SmallString<100> buf; - llvm::raw_svector_ostream os(buf); + SmallString<100> Buf; + llvm::raw_svector_ostream Out(Buf); SmallVector<SourceRange, 2> Ranges; switch (S->getStmtClass()) { case Stmt::ArraySubscriptExprClass: { - os << "Array access"; + Out << "Array access"; const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S); - AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), - State.get(), N->getLocationContext()); - os << DerefStr1; + AddDerefSource(Out, Ranges, AE->getBase()->IgnoreParenCasts(), State.get(), + N->getLocationContext()); + Out << " results in " << BT.getArrayMsg(); break; } case Stmt::ArraySectionExprClass: { - os << "Array access"; + Out << "Array access"; const ArraySectionExpr *AE = cast<ArraySectionExpr>(S); - AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), - State.get(), N->getLocationContext()); - os << DerefStr1; + AddDerefSource(Out, Ranges, AE->getBase()->IgnoreParenCasts(), State.get(), + N->getLocationContext()); + Out << " results in " << BT.getArrayMsg(); break; } case Stmt::UnaryOperatorClass: { - os << BT->getDescription(); + Out << BT.getDescription(); const UnaryOperator *U = cast<UnaryOperator>(S); - AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), - State.get(), N->getLocationContext(), true); + AddDerefSource(Out, Ranges, U->getSubExpr()->IgnoreParens(), State.get(), + N->getLocationContext(), true); break; } case Stmt::MemberExprClass: { const MemberExpr *M = cast<MemberExpr>(S); if (M->isArrow() || isDeclRefExprToReference(M->getBase())) { - os << "Access to field '" << M->getMemberNameInfo() << "'" << DerefStr2; - AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), - State.get(), N->getLocationContext(), true); + Out << "Access to field '" << M->getMemberNameInfo() << "' results in " + << BT.getFieldMsg(); + AddDerefSource(Out, Ranges, M->getBase()->IgnoreParenCasts(), State.get(), + N->getLocationContext(), true); } break; } case Stmt::ObjCIvarRefExprClass: { const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S); - os << "Access to instance variable '" << *IV->getDecl() << "'" << DerefStr2; - AddDerefSource(os, Ranges, IV->getBase()->IgnoreParenCasts(), - State.get(), N->getLocationContext(), true); + Out << "Access to instance variable '" << *IV->getDecl() << "' results in " + << BT.getFieldMsg(); + AddDerefSource(Out, Ranges, IV->getBase()->IgnoreParenCasts(), State.get(), + N->getLocationContext(), true); break; } default: break; } - auto report = std::make_unique<PathSensitiveBugReport>( - *BT, buf.empty() ? BT->getDescription() : buf.str(), N); + auto BR = std::make_unique<PathSensitiveBugReport>( + BT, Buf.empty() ? BT.getDescription() : Buf.str(), N); - bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *report); + bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *BR); for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I!=E; ++I) - report->addRange(*I); + BR->addRange(*I); - C.emitReport(std::move(report)); + C.emitReport(std::move(BR)); } void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, @@ -275,7 +261,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, if (l.isUndef()) { const Expr *DerefExpr = getDereferenceExpr(S); if (!suppressReport(C, DerefExpr)) - reportBug(DerefKind::UndefinedPointerValue, C.getState(), DerefExpr, C); + reportBug(UndefBug, C.getState(), DerefExpr, C); return; } @@ -296,7 +282,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, // we call an "explicit" null dereference. const Expr *expr = getDereferenceExpr(S); if (!suppressReport(C, expr)) { - reportBug(DerefKind::NullPointer, nullState, expr, C); + reportBug(NullBug, nullState, expr, C); return; } } @@ -314,7 +300,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, if (location.isConstant()) { const Expr *DerefExpr = getDereferenceExpr(S, isLoad); if (!suppressReport(C, DerefExpr)) - reportBug(DerefKind::FixedAddress, notNullState, DerefExpr, C); + reportBug(FixedAddressBug, notNullState, DerefExpr, C); return; } @@ -330,7 +316,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, // One should never write to label addresses. if (auto Label = L.getAs<loc::GotoLabel>()) { - reportBug(DerefKind::AddressOfLabel, C.getState(), S, C); + reportBug(LabelBug, C.getState(), S, C); return; } @@ -351,7 +337,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, if (!StNonNull) { const Expr *expr = getDereferenceExpr(S, /*IsBind=*/true); if (!suppressReport(C, expr)) { - reportBug(DerefKind::NullPointer, StNull, expr, C); + reportBug(NullBug, StNull, expr, C); return; } } @@ -369,7 +355,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, if (V.isConstant()) { const Expr *DerefExpr = getDereferenceExpr(S, true); if (!suppressReport(C, DerefExpr)) - reportBug(DerefKind::FixedAddress, State, DerefExpr, C); + reportBug(FixedAddressBug, State, DerefExpr, C); return; } @@ -392,26 +378,8 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, C.addTransition(State, this); } -void ento::registerDereferenceModeling(CheckerManager &Mgr) { - Mgr.registerChecker<DereferenceChecker>(); -} - -bool ento::shouldRegisterDereferenceModeling(const CheckerManager &) { - return true; -} - void ento::registerNullDereferenceChecker(CheckerManager &Mgr) { - auto *Chk = Mgr.getChecker<DereferenceChecker>(); - Chk->CheckNullDereference = true; - Chk->BT_Null.reset(new BugType(Mgr.getCurrentCheckerName(), - "Dereference of null pointer", - categories::LogicError)); - Chk->BT_Undef.reset(new BugType(Mgr.getCurrentCheckerName(), - "Dereference of undefined pointer value", - categories::LogicError)); - Chk->BT_Label.reset(new BugType(Mgr.getCurrentCheckerName(), - "Dereference of the address of a label", - categories::LogicError)); + Mgr.getChecker<DereferenceChecker>()->NullDerefChecker.enable(Mgr); } bool ento::shouldRegisterNullDereferenceChecker(const CheckerManager &) { @@ -419,11 +387,7 @@ bool ento::shouldRegisterNullDereferenceChecker(const CheckerManager &) { } void ento::registerFixedAddressDereferenceChecker(CheckerManager &Mgr) { - auto *Chk = Mgr.getChecker<DereferenceChecker>(); - Chk->CheckFixedDereference = true; - Chk->BT_FixedAddress.reset(new BugType(Mgr.getCurrentCheckerName(), - "Dereference of a fixed address", - categories::LogicError)); + Mgr.getChecker<DereferenceChecker>()->FixedDerefChecker.enable(Mgr); } bool ento::shouldRegisterFixedAddressDereferenceChecker( diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index a7704da..369d619 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -2693,7 +2693,7 @@ void MallocChecker::HandleUseAfterFree(CheckerContext &C, SourceRange Range, Frontend->UseFreeBug, AF.Kind == AF_InnerBuffer ? "Inner pointer of container used after re/deallocation" - : "Use of memory after it is freed", + : "Use of memory after it is released", N); R->markInteresting(Sym); @@ -2721,8 +2721,8 @@ void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range, if (ExplodedNode *N = C.generateErrorNode()) { auto R = std::make_unique<PathSensitiveBugReport>( Frontend->DoubleFreeBug, - (Released ? "Attempt to free released memory" - : "Attempt to free non-owned memory"), + (Released ? "Attempt to release already released memory" + : "Attempt to release non-owned memory"), N); if (Range.isValid()) R->addRange(Range); |