diff options
Diffstat (limited to 'clang/lib')
96 files changed, 1728 insertions, 904 deletions
diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp index 3288585..d474605 100644 --- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp +++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp @@ -137,21 +137,21 @@ int32_t ByteCodeEmitter::getOffset(LabelTy Label) { template <typename T> static void emit(Program &P, std::vector<std::byte> &Code, const T &Val, bool &Success) { + size_t ValPos = Code.size(); size_t Size; if constexpr (std::is_pointer_v<T>) - Size = sizeof(uint32_t); + Size = align(sizeof(uint32_t)); else - Size = sizeof(T); + Size = align(sizeof(T)); - if (Code.size() + Size > std::numeric_limits<unsigned>::max()) { + if (ValPos + Size > std::numeric_limits<unsigned>::max()) { Success = false; return; } // Access must be aligned! - size_t ValPos = align(Code.size()); - Size = align(Size); + assert(aligned(ValPos)); assert(aligned(ValPos + Size)); Code.resize(ValPos + Size); @@ -168,17 +168,16 @@ static void emit(Program &P, std::vector<std::byte> &Code, const T &Val, template <typename T> static void emitSerialized(std::vector<std::byte> &Code, const T &Val, bool &Success) { - size_t Size = Val.bytesToSerialize(); + size_t ValPos = Code.size(); + size_t Size = align(Val.bytesToSerialize()); - if (Code.size() + Size > std::numeric_limits<unsigned>::max()) { + if (ValPos + Size > std::numeric_limits<unsigned>::max()) { Success = false; return; } // Access must be aligned! - assert(aligned(Code.size())); - size_t ValPos = Code.size(); - Size = align(Size); + assert(aligned(ValPos)); assert(aligned(ValPos + Size)); Code.resize(ValPos + Size); diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index d0ddb2e..6e451ac 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -106,25 +106,14 @@ bool InitLink::emit(Compiler<Emitter> *Ctx, const Expr *E) const { return true; } -/// Scope managing label targets. -template <class Emitter> class LabelScope { -public: - virtual ~LabelScope() {} - -protected: - LabelScope(Compiler<Emitter> *Ctx) : Ctx(Ctx) {} - /// Compiler instance. - Compiler<Emitter> *Ctx; -}; - /// Sets the context for break/continue statements. -template <class Emitter> class LoopScope final : public LabelScope<Emitter> { +template <class Emitter> class LoopScope final { public: using LabelTy = typename Compiler<Emitter>::LabelTy; using OptLabelTy = typename Compiler<Emitter>::OptLabelTy; LoopScope(Compiler<Emitter> *Ctx, LabelTy BreakLabel, LabelTy ContinueLabel) - : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel), + : Ctx(Ctx), OldBreakLabel(Ctx->BreakLabel), OldContinueLabel(Ctx->ContinueLabel), OldBreakVarScope(Ctx->BreakVarScope), OldContinueVarScope(Ctx->ContinueVarScope) { @@ -142,6 +131,7 @@ public: } private: + Compiler<Emitter> *Ctx; OptLabelTy OldBreakLabel; OptLabelTy OldContinueLabel; VariableScope<Emitter> *OldBreakVarScope; @@ -149,7 +139,7 @@ private: }; // Sets the context for a switch scope, mapping labels. -template <class Emitter> class SwitchScope final : public LabelScope<Emitter> { +template <class Emitter> class SwitchScope final { public: using LabelTy = typename Compiler<Emitter>::LabelTy; using OptLabelTy = typename Compiler<Emitter>::OptLabelTy; @@ -157,7 +147,7 @@ public: SwitchScope(Compiler<Emitter> *Ctx, CaseMap &&CaseLabels, LabelTy BreakLabel, OptLabelTy DefaultLabel) - : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel), + : Ctx(Ctx), OldBreakLabel(Ctx->BreakLabel), OldDefaultLabel(this->Ctx->DefaultLabel), OldCaseLabels(std::move(this->Ctx->CaseLabels)), OldLabelVarScope(Ctx->BreakVarScope) { @@ -175,6 +165,7 @@ public: } private: + Compiler<Emitter> *Ctx; OptLabelTy OldBreakLabel; OptLabelTy OldDefaultLabel; CaseMap OldCaseLabels; @@ -340,6 +331,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { } case CK_FloatingToIntegral: { + if (!CE->getType()->isIntegralOrEnumerationType()) + return false; if (!this->visit(SubExpr)) return false; PrimType ToT = classifyPrim(CE); @@ -457,13 +450,17 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { assert(isPtrType(*FromT)); assert(isPtrType(*ToT)); if (FromT == ToT) { - if (CE->getType()->isVoidPointerType()) + if (CE->getType()->isVoidPointerType() && + !SubExprTy->isFunctionPointerType()) { return this->delegate(SubExpr); + } if (!this->visit(SubExpr)) return false; - if (CE->getType()->isFunctionPointerType()) - return true; + if (CE->getType()->isFunctionPointerType() || + SubExprTy->isFunctionPointerType()) { + return this->emitFnPtrCast(CE); + } if (FromT == PT_Ptr) return this->emitPtrPtrCast(SubExprTy->isVoidPointerType(), CE); return true; @@ -1374,10 +1371,15 @@ bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) { // BitAdd/BitOr/BitXor/Shl/Shr doesn't support bool type, we need perform the // integer promotion. bool NeedIntPromot = ElemT == PT_Bool && (E->isBitwiseOp() || E->isShiftOp()); - QualType PromotTy = - Ctx.getASTContext().getPromotedIntegerType(Ctx.getASTContext().BoolTy); - PrimType PromotT = classifyPrim(PromotTy); - PrimType OpT = NeedIntPromot ? PromotT : ElemT; + QualType PromotTy; + PrimType PromotT = PT_Bool; + PrimType OpT = ElemT; + if (NeedIntPromot) { + PromotTy = + Ctx.getASTContext().getPromotedIntegerType(Ctx.getASTContext().BoolTy); + PromotT = classifyPrim(PromotTy); + OpT = PromotT; + } auto getElem = [=](unsigned Offset, PrimType ElemT, unsigned Index) { if (!this->emitGetLocal(PT_Ptr, Offset, E)) @@ -1763,6 +1765,9 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, if (Inits.size() == 1 && E->getType() == Inits[0]->getType()) return this->delegate(Inits[0]); + if (!R) + return false; + auto initPrimitiveField = [=](const Record::Field *FieldToInit, const Expr *Init, PrimType T, bool Activate = false) -> bool { diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index 3a26342..16f108f 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -21,7 +21,6 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/AST/StmtVisitor.h" -#include "clang/Basic/TargetInfo.h" namespace clang { class QualType; diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp index 5b9f445..7403e90 100644 --- a/clang/lib/AST/ByteCode/Descriptor.cpp +++ b/clang/lib/AST/ByteCode/Descriptor.cpp @@ -21,14 +21,31 @@ using namespace clang; using namespace clang::interp; +template <typename T> static constexpr bool needsCtor() { + if constexpr (std::is_same_v<T, Integral<8, true>> || + std::is_same_v<T, Integral<8, false>> || + std::is_same_v<T, Integral<16, true>> || + std::is_same_v<T, Integral<16, false>> || + std::is_same_v<T, Integral<32, true>> || + std::is_same_v<T, Integral<32, false>> || + std::is_same_v<T, Integral<64, true>> || + std::is_same_v<T, Integral<64, false>> || + std::is_same_v<T, Boolean>) + return false; + + return true; +} + template <typename T> static void ctorTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool, const Descriptor *) { + static_assert(needsCtor<T>()); new (Ptr) T(); } template <typename T> static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) { + static_assert(needsCtor<T>()); reinterpret_cast<T *>(Ptr)->~T(); } @@ -45,9 +62,11 @@ static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool, const Descriptor *D) { new (Ptr) InitMapPtr(std::nullopt); - Ptr += sizeof(InitMapPtr); - for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { - new (&reinterpret_cast<T *>(Ptr)[I]) T(); + if constexpr (needsCtor<T>()) { + Ptr += sizeof(InitMapPtr); + for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { + new (&reinterpret_cast<T *>(Ptr)[I]) T(); + } } } @@ -57,9 +76,12 @@ static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) { if (IMP) IMP = std::nullopt; - Ptr += sizeof(InitMapPtr); - for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { - reinterpret_cast<T *>(Ptr)[I].~T(); + + if constexpr (needsCtor<T>()) { + Ptr += sizeof(InitMapPtr); + for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { + reinterpret_cast<T *>(Ptr)[I].~T(); + } } } @@ -74,10 +96,14 @@ static void moveArrayTy(Block *, std::byte *Src, std::byte *Dst, } Src += sizeof(InitMapPtr); Dst += sizeof(InitMapPtr); - for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { - auto *SrcPtr = &reinterpret_cast<T *>(Src)[I]; - auto *DstPtr = &reinterpret_cast<T *>(Dst)[I]; - new (DstPtr) T(std::move(*SrcPtr)); + if constexpr (!needsCtor<T>()) { + std::memcpy(Dst, Src, D->getNumElems() * D->getElemSize()); + } else { + for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { + auto *SrcPtr = &reinterpret_cast<T *>(Src)[I]; + auto *DstPtr = &reinterpret_cast<T *>(Dst)[I]; + new (DstPtr) T(std::move(*SrcPtr)); + } } } diff --git a/clang/lib/AST/ByteCode/DynamicAllocator.cpp b/clang/lib/AST/ByteCode/DynamicAllocator.cpp index 169250c..9b8b664 100644 --- a/clang/lib/AST/ByteCode/DynamicAllocator.cpp +++ b/clang/lib/AST/ByteCode/DynamicAllocator.cpp @@ -13,6 +13,25 @@ using namespace clang; using namespace clang::interp; +// FIXME: There is a peculiar problem with the way we track pointers +// to blocks and the way we allocate dynamic memory. +// +// When we have code like this: +// while (true) { +// char *buffer = new char[1024]; +// delete[] buffer; +// } +// +// We have a local variable 'buffer' pointing to the heap allocated memory. +// When deallocating the memory via delete[], that local variable still +// points to the memory, which means we will create a DeadBlock for it and move +// it over to that block, essentially duplicating the allocation. Moving +// the data is also slow. +// +// However, when we actually try to access the allocation after it has been +// freed, we need the block to still exist (alive or dead) so we can tell +// that it's a dynamic allocation. + DynamicAllocator::~DynamicAllocator() { cleanup(); } void DynamicAllocator::cleanup() { diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 2602ed7..9a325ab 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -25,7 +25,6 @@ #include "InterpStack.h" #include "InterpState.h" #include "MemberPointer.h" -#include "Opcode.h" #include "PrimType.h" #include "Program.h" #include "State.h" @@ -1131,8 +1130,9 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end) << LHS.toDiagnosticString(S.getASTContext()); return false; - } else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() && - LHS.getOffset() == 0) { + } + if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() && + LHS.getOffset() == 0) { const SourceInfo &Loc = S.Current->getSource(OpPC); S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end) << RHS.toDiagnosticString(S.getASTContext()); @@ -1150,8 +1150,9 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { const SourceInfo &Loc = S.Current->getSource(OpPC); S.FFDiag(Loc, diag::note_constexpr_literal_comparison); return false; - } else if (const auto *CE = dyn_cast<CallExpr>(E); - CE && IsOpaqueConstantCall(CE)) { + } + if (const auto *CE = dyn_cast<CallExpr>(E); + CE && IsOpaqueConstantCall(CE)) { const SourceInfo &Loc = S.Current->getSource(OpPC); S.FFDiag(Loc, diag::note_constexpr_opaque_call_comparison) << P.toDiagnosticString(S.getASTContext()); @@ -2681,6 +2682,14 @@ static inline bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC) { return true; } +static inline bool FnPtrCast(InterpState &S, CodePtr OpPC) { + const SourceInfo &E = S.Current->getSource(OpPC); + S.CCEDiag(E, diag::note_constexpr_invalid_cast) + << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret + << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC); + return true; +} + static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) { const auto &Ptr = S.Stk.peek<Pointer>(); @@ -3266,7 +3275,8 @@ inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, S.CCEDiag(Loc, diag::note_constexpr_invalid_cast) << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC); return !Fatal; - } else if (Kind == CastKind::Volatile) { + } + if (Kind == CastKind::Volatile) { if (!S.checkingPotentialConstantExpression()) { const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC)); if (S.getLangOpts().CPlusPlus) @@ -3277,7 +3287,8 @@ inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, } return false; - } else if (Kind == CastKind::Dynamic) { + } + if (Kind == CastKind::Dynamic) { assert(!S.getLangOpts().CPlusPlus20); S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast) << diag::ConstexprInvalidCastKind::Dynamic; diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp index 3010847..32ad07b 100644 --- a/clang/lib/AST/ByteCode/InterpState.cpp +++ b/clang/lib/AST/ByteCode/InterpState.cpp @@ -77,27 +77,27 @@ void InterpState::deallocate(Block *B) { const Descriptor *Desc = B->getDescriptor(); assert(Desc); + // The block might have a pointer saved in a field in its data + // that points to the block itself. We call the dtor first, + // which will destroy all the data but leave InlineDescriptors + // intact. If the block THEN still has pointers, we create a + // DeadBlock for it. + if (B->IsInitialized) + B->invokeDtor(); + if (B->hasPointers()) { size_t Size = B->getSize(); - // Allocate a new block, transferring over pointers. char *Memory = reinterpret_cast<char *>(std::malloc(sizeof(DeadBlock) + Size)); auto *D = new (Memory) DeadBlock(DeadBlocks, B); - std::memset(D->B.rawData(), 0, D->B.getSize()); - - // Move data and metadata from the old block to the new (dead)block. - if (B->IsInitialized && Desc->MoveFn) { - Desc->MoveFn(B, B->data(), D->data(), Desc); - if (Desc->getMetadataSize() > 0) - std::memcpy(D->rawData(), B->rawData(), Desc->getMetadataSize()); - } + // Since the block doesn't hold any actual data anymore, we can just + // memcpy() everything over. + std::memcpy(D->rawData(), B->rawData(), Desc->getAllocSize()); D->B.IsInitialized = B->IsInitialized; // We moved the contents over to the DeadBlock. B->IsInitialized = false; - } else if (B->IsInitialized) { - B->invokeDtor(); } } diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index abfed77..95a4433 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -412,7 +412,7 @@ def CheckDecl : Opcode { def CheckEnumValue : Opcode { let Args = [ArgEnumDecl]; - let Types = [FixedSizeIntegralTypeClass]; + let Types = [IntegralTypeClass]; let HasGroup = 1; } @@ -735,6 +735,8 @@ def PtrPtrCast : Opcode { } +def FnPtrCast : Opcode; + def DecayPtr : Opcode { let Types = [PtrTypeClass, PtrTypeClass]; let HasGroup = 1; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 83fcd87..1588be4 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -5988,11 +5988,10 @@ bool clang::IsArmStreamingFunction(const FunctionDecl *FD, if (FD->hasAttr<ArmLocallyStreamingAttr>()) return true; - if (const Type *Ty = FD->getType().getTypePtrOrNull()) - if (const auto *FPT = Ty->getAs<FunctionProtoType>()) - if (FPT->getAArch64SMEAttributes() & - FunctionType::SME_PStateSMEnabledMask) - return true; + assert(!FD->getType().isNull() && "Expected a valid FunctionDecl"); + if (const auto *FPT = FD->getType()->getAs<FunctionProtoType>()) + if (FPT->getAArch64SMEAttributes() & FunctionType::SME_PStateSMEnabledMask) + return true; return false; } diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index d85655b..cd9672d 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -4233,8 +4233,15 @@ bool Expr::isSameComparisonOperand(const Expr* E1, const Expr* E2) { // template parameters. const auto *DRE1 = cast<DeclRefExpr>(E1); const auto *DRE2 = cast<DeclRefExpr>(E2); - return DRE1->isPRValue() && DRE2->isPRValue() && - DRE1->getDecl() == DRE2->getDecl(); + + if (DRE1->getDecl() != DRE2->getDecl()) + return false; + + if ((DRE1->isPRValue() && DRE2->isPRValue()) || + (DRE1->isLValue() && DRE2->isLValue())) + return true; + + return false; } case ImplicitCastExprClass: { // Peel off implicit casts. @@ -4244,7 +4251,8 @@ bool Expr::isSameComparisonOperand(const Expr* E1, const Expr* E2) { if (!ICE1 || !ICE2) return false; if (ICE1->getCastKind() != ICE2->getCastKind()) - return false; + return isSameComparisonOperand(ICE1->IgnoreParenImpCasts(), + ICE2->IgnoreParenImpCasts()); E1 = ICE1->getSubExpr()->IgnoreParens(); E2 = ICE2->getSubExpr()->IgnoreParens(); // The final cast must be one of these types. diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 9808298..20b7c44 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9741,10 +9741,19 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_AddressSpaceConversion: if (!Visit(SubExpr)) return false; - // Bitcasts to cv void* are static_casts, not reinterpret_casts, so are - // permitted in constant expressions in C++11. Bitcasts from cv void* are - // also static_casts, but we disallow them as a resolution to DR1312. - if (!E->getType()->isVoidPointerType()) { + if (E->getType()->isFunctionPointerType() || + SubExpr->getType()->isFunctionPointerType()) { + // Casting between two function pointer types, or between a function + // pointer and an object pointer, is always a reinterpret_cast. + CCEDiag(E, diag::note_constexpr_invalid_cast) + << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret + << Info.Ctx.getLangOpts().CPlusPlus; + Result.Designator.setInvalid(); + } else if (!E->getType()->isVoidPointerType()) { + // Bitcasts to cv void* are static_casts, not reinterpret_casts, so are + // permitted in constant expressions in C++11. Bitcasts from cv void* are + // also static_casts, but we disallow them as a resolution to DR1312. + // // In some circumstances, we permit casting from void* to cv1 T*, when the // actual pointee object is actually a cv2 T. bool HasValidResult = !Result.InvalidBase && !Result.Designator.Invalid && @@ -16849,31 +16858,31 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) { CheckMemoryLeaks(Info); } -static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result, +static bool FastEvaluateAsRValue(const Expr *Exp, APValue &Result, const ASTContext &Ctx, bool &IsConst) { // Fast-path evaluations of integer literals, since we sometimes see files // containing vast quantities of these. if (const auto *L = dyn_cast<IntegerLiteral>(Exp)) { - Result.Val = APValue(APSInt(L->getValue(), - L->getType()->isUnsignedIntegerType())); + Result = + APValue(APSInt(L->getValue(), L->getType()->isUnsignedIntegerType())); IsConst = true; return true; } if (const auto *L = dyn_cast<CXXBoolLiteralExpr>(Exp)) { - Result.Val = APValue(APSInt(APInt(1, L->getValue()))); + Result = APValue(APSInt(APInt(1, L->getValue()))); IsConst = true; return true; } if (const auto *FL = dyn_cast<FloatingLiteral>(Exp)) { - Result.Val = APValue(FL->getValue()); + Result = APValue(FL->getValue()); IsConst = true; return true; } if (const auto *L = dyn_cast<CharacterLiteral>(Exp)) { - Result.Val = APValue(Ctx.MakeIntValue(L->getValue(), L->getType())); + Result = APValue(Ctx.MakeIntValue(L->getValue(), L->getType())); IsConst = true; return true; } @@ -16882,7 +16891,7 @@ static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result, if (CE->hasAPValueResult()) { APValue APV = CE->getAPValueResult(); if (!APV.isLValue()) { - Result.Val = std::move(APV); + Result = std::move(APV); IsConst = true; return true; } @@ -16912,7 +16921,7 @@ static bool EvaluateAsRValue(const Expr *E, Expr::EvalResult &Result, const ASTContext &Ctx, EvalInfo &Info) { assert(!E->isValueDependent()); bool IsConst; - if (FastEvaluateAsRValue(E, Result, Ctx, IsConst)) + if (FastEvaluateAsRValue(E, Result.Val, Ctx, IsConst)) return IsConst; return EvaluateAsRValue(Info, E, Result.Val); @@ -17069,7 +17078,8 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx, assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); bool IsConst; - if (FastEvaluateAsRValue(this, Result, Ctx, IsConst) && Result.Val.hasValue()) + if (FastEvaluateAsRValue(this, Result.Val, Ctx, IsConst) && + Result.Val.hasValue()) return true; ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsConstantExpr"); @@ -17284,7 +17294,7 @@ void Expr::EvaluateForOverflow(const ASTContext &Ctx) const { ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateForOverflow"); bool IsConst; EvalResult EVResult; - if (!FastEvaluateAsRValue(this, EVResult, Ctx, IsConst)) { + if (!FastEvaluateAsRValue(this, EVResult.Val, Ctx, IsConst)) { EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects); Info.CheckingForUndefinedBehavior = true; (void)::EvaluateAsRValue(Info, this, EVResult.Val); @@ -17303,8 +17313,7 @@ bool Expr::EvalResult::isGlobalLValue() const { /// comma, etc // CheckICE - This function does the fundamental ICE checking: the returned -// ICEDiag contains an ICEKind indicating whether the expression is an ICE, -// and a (possibly null) SourceLocation indicating the location of the problem. +// ICEDiag contains an ICEKind indicating whether the expression is an ICE. // // Note that to reduce code duplication, this helper does no evaluation // itself; the caller checks whether the expression is evaluatable, and @@ -17768,60 +17777,51 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { /// Evaluate an expression as a C++11 integral constant expression. static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx, const Expr *E, - llvm::APSInt *Value, - SourceLocation *Loc) { - if (!E->getType()->isIntegralOrUnscopedEnumerationType()) { - if (Loc) *Loc = E->getExprLoc(); + llvm::APSInt *Value) { + if (!E->getType()->isIntegralOrUnscopedEnumerationType()) return false; - } APValue Result; - if (!E->isCXX11ConstantExpr(Ctx, &Result, Loc)) + if (!E->isCXX11ConstantExpr(Ctx, &Result)) return false; - if (!Result.isInt()) { - if (Loc) *Loc = E->getExprLoc(); + if (!Result.isInt()) return false; - } if (Value) *Value = Result.getInt(); return true; } -bool Expr::isIntegerConstantExpr(const ASTContext &Ctx, - SourceLocation *Loc) const { +bool Expr::isIntegerConstantExpr(const ASTContext &Ctx) const { assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); ExprTimeTraceScope TimeScope(this, Ctx, "isIntegerConstantExpr"); if (Ctx.getLangOpts().CPlusPlus11) - return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, nullptr, Loc); + return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, nullptr); ICEDiag D = CheckICE(this, Ctx); - if (D.Kind != IK_ICE) { - if (Loc) *Loc = D.Loc; + if (D.Kind != IK_ICE) return false; - } return true; } std::optional<llvm::APSInt> -Expr::getIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc) const { +Expr::getIntegerConstantExpr(const ASTContext &Ctx) const { if (isValueDependent()) { // Expression evaluator can't succeed on a dependent expression. return std::nullopt; } - APSInt Value; - if (Ctx.getLangOpts().CPlusPlus11) { - if (EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value, Loc)) + APSInt Value; + if (EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value)) return Value; return std::nullopt; } - if (!isIntegerConstantExpr(Ctx, Loc)) + if (!isIntegerConstantExpr(Ctx)) return std::nullopt; // The only possible side-effects here are due to UB discovered in the @@ -17846,8 +17846,7 @@ bool Expr::isCXX98IntegralConstantExpr(const ASTContext &Ctx) const { return CheckICE(this, Ctx).Kind == IK_ICE; } -bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result, - SourceLocation *Loc) const { +bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result) const { assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); @@ -17855,28 +17854,27 @@ bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result, // issues. assert(Ctx.getLangOpts().CPlusPlus); + bool IsConst; + APValue Scratch; + if (FastEvaluateAsRValue(this, Scratch, Ctx, IsConst) && Scratch.hasValue()) { + if (Result) + *Result = Scratch; + return true; + } + // Build evaluation settings. Expr::EvalStatus Status; SmallVector<PartialDiagnosticAt, 8> Diags; Status.Diag = &Diags; EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpression); - APValue Scratch; bool IsConstExpr = ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch) && // FIXME: We don't produce a diagnostic for this, but the callers that // call us on arbitrary full-expressions should generally not care. Info.discardCleanups() && !Status.HasSideEffects; - if (!Diags.empty()) { - IsConstExpr = false; - if (Loc) *Loc = Diags[0].first; - } else if (!IsConstExpr) { - // FIXME: This shouldn't happen. - if (Loc) *Loc = getExprLoc(); - } - - return IsConstExpr; + return IsConstExpr && Diags.empty(); } bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx, diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index bc47e05..e6ea0ad 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -1298,8 +1298,7 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(GlobalDecl GD, Name += "<unnamed-type-"; Name += TND->getName(); } else if (isa<EnumDecl>(TD) && - cast<EnumDecl>(TD)->enumerator_begin() != - cast<EnumDecl>(TD)->enumerator_end()) { + !cast<EnumDecl>(TD)->enumerators().empty()) { // Anonymous non-empty enums mangle in the first enumerator. auto *ED = cast<EnumDecl>(TD); Name += "<unnamed-enum-"; diff --git a/clang/lib/Analysis/RetainSummaryManager.cpp b/clang/lib/Analysis/RetainSummaryManager.cpp index 987f894..688efe4 100644 --- a/clang/lib/Analysis/RetainSummaryManager.cpp +++ b/clang/lib/Analysis/RetainSummaryManager.cpp @@ -147,8 +147,7 @@ static bool isSubclass(const Decl *D, static bool isExactClass(const Decl *D, StringRef ClassName) { using namespace ast_matchers; - DeclarationMatcher sameClassM = - cxxRecordDecl(hasName(std::string(ClassName))); + DeclarationMatcher sameClassM = cxxRecordDecl(hasName(ClassName)); return !(match(sameClassM, *D, D->getASTContext()).empty()); } diff --git a/clang/lib/Basic/Cuda.cpp b/clang/lib/Basic/Cuda.cpp index 53b36d3..dc81b71 100644 --- a/clang/lib/Basic/Cuda.cpp +++ b/clang/lib/Basic/Cuda.cpp @@ -44,6 +44,7 @@ static const CudaVersionMapEntry CudaNameVersionMap[] = { CUDA_ENTRY(12, 5), CUDA_ENTRY(12, 6), CUDA_ENTRY(12, 8), + CUDA_ENTRY(12, 9), {"", CudaVersion::NEW, llvm::VersionTuple(std::numeric_limits<int>::max())}, {"unknown", CudaVersion::UNKNOWN, {}} // End of list tombstone. }; @@ -119,6 +120,11 @@ CudaVersion MinVersionForOffloadArch(OffloadArch A) { case OffloadArch::SM_120: case OffloadArch::SM_120a: return CudaVersion::CUDA_128; + case OffloadArch::SM_103: + case OffloadArch::SM_103a: + case OffloadArch::SM_121: + case OffloadArch::SM_121a: + return CudaVersion::CUDA_129; default: llvm_unreachable("invalid enum"); } diff --git a/clang/lib/Basic/OffloadArch.cpp b/clang/lib/Basic/OffloadArch.cpp index dce9ffa..4348178 100644 --- a/clang/lib/Basic/OffloadArch.cpp +++ b/clang/lib/Basic/OffloadArch.cpp @@ -33,8 +33,12 @@ static const OffloadArchToStringMap ArchNames[] = { SM(100a), // Blackwell SM(101), // Blackwell SM(101a), // Blackwell + SM(103), // Blackwell + SM(103a), // Blackwell SM(120), // Blackwell SM(120a), // Blackwell + SM(121), // Blackwell + SM(121a), // Blackwell GFX(600), // gfx600 GFX(601), // gfx601 GFX(602), // gfx602 diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp index b2b1488..343c26e 100644 --- a/clang/lib/Basic/SourceManager.cpp +++ b/clang/lib/Basic/SourceManager.cpp @@ -2366,23 +2366,21 @@ size_t SourceManager::getDataStructureSizes() const { SourceManagerForFile::SourceManagerForFile(StringRef FileName, StringRef Content) { - // This is referenced by `FileMgr` and will be released by `FileMgr` when it - // is deleted. - IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( - new llvm::vfs::InMemoryFileSystem); + auto InMemoryFileSystem = + llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); InMemoryFileSystem->addFile( FileName, 0, llvm::MemoryBuffer::getMemBuffer(Content, FileName, /*RequiresNullTerminator=*/false)); // This is passed to `SM` as reference, so the pointer has to be referenced // in `Environment` so that `FileMgr` can out-live this function scope. - FileMgr = - std::make_unique<FileManager>(FileSystemOptions(), InMemoryFileSystem); + FileMgr = std::make_unique<FileManager>(FileSystemOptions(), + std::move(InMemoryFileSystem)); DiagOpts = std::make_unique<DiagnosticOptions>(); // This is passed to `SM` as reference, so the pointer has to be referenced // by `Environment` due to the same reason above. - Diagnostics = std::make_unique<DiagnosticsEngine>( - IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), *DiagOpts); + Diagnostics = + std::make_unique<DiagnosticsEngine>(DiagnosticIDs::create(), *DiagOpts); SourceMgr = std::make_unique<SourceManager>(*Diagnostics, *FileMgr); FileEntryRef FE = llvm::cantFail(FileMgr->getFileRef(FileName)); FileID ID = diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp index 6bec2fa..75fdf38 100644 --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -133,19 +133,24 @@ void ARMTargetInfo::setArchInfo(llvm::ARM::ArchKind Kind) { } void ARMTargetInfo::setAtomic() { - // when triple does not specify a sub arch, - // then we are not using inline atomics - bool ShouldUseInlineAtomic = - (ArchISA == llvm::ARM::ISAKind::ARM && ArchVersion >= 6) || - (ArchISA == llvm::ARM::ISAKind::THUMB && ArchVersion >= 7); - // Cortex M does not support 8 byte atomics, while general Thumb2 does. if (ArchProfile == llvm::ARM::ProfileKind::M) { + // M-class only ever supports 32-bit atomics. Cortex-M0 doesn't have + // any atomics. MaxAtomicPromoteWidth = 32; - if (ShouldUseInlineAtomic) + if (ArchVersion >= 7) MaxAtomicInlineWidth = 32; } else { + // A-class targets have up to 64-bit atomics. + // + // On Linux, 64-bit atomics are always available through kernel helpers + // (which are lock-free). Otherwise, atomics are available on v6 or later. + // + // (Thumb doesn't matter; for Thumbv6, we just use a library call which + // switches out of Thumb mode.) + // + // This should match setMaxAtomicSizeInBitsSupported() in the backend. MaxAtomicPromoteWidth = 64; - if (ShouldUseInlineAtomic) + if (getTriple().getOS() == llvm::Triple::Linux || ArchVersion >= 6) MaxAtomicInlineWidth = 64; } } diff --git a/clang/lib/Basic/Targets/NVPTX.cpp b/clang/lib/Basic/Targets/NVPTX.cpp index 54b39fd..79995cc 100644 --- a/clang/lib/Basic/Targets/NVPTX.cpp +++ b/clang/lib/Basic/Targets/NVPTX.cpp @@ -295,10 +295,16 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts, return "1000"; case OffloadArch::SM_101: case OffloadArch::SM_101a: - return "1010"; + return "1010"; + case OffloadArch::SM_103: + case OffloadArch::SM_103a: + return "1030"; case OffloadArch::SM_120: case OffloadArch::SM_120a: - return "1200"; + return "1200"; + case OffloadArch::SM_121: + case OffloadArch::SM_121a: + return "1210"; } llvm_unreachable("unhandled OffloadArch"); }(); @@ -307,7 +313,9 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts, case OffloadArch::SM_90a: case OffloadArch::SM_100a: case OffloadArch::SM_101a: + case OffloadArch::SM_103a: case OffloadArch::SM_120a: + case OffloadArch::SM_121a: Builder.defineMacro("__CUDA_ARCH_FEAT_SM" + CUDAArchCode.drop_back() + "_ALL", "1"); break; default: diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp index e362350e..55ffe1d 100644 --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -59,12 +59,12 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const { .Case("exception-handling", HasExceptionHandling) .Case("extended-const", HasExtendedConst) .Case("fp16", HasFP16) + .Case("gc", HasGC) .Case("multimemory", HasMultiMemory) .Case("multivalue", HasMultivalue) .Case("mutable-globals", HasMutableGlobals) .Case("nontrapping-fptoint", HasNontrappingFPToInt) .Case("reference-types", HasReferenceTypes) - .Case("gc", HasGC) .Case("relaxed-simd", SIMDLevel >= RelaxedSIMD) .Case("sign-ext", HasSignExt) .Case("simd128", SIMDLevel >= SIMD128) @@ -99,6 +99,8 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__wasm_multimemory__"); if (HasFP16) Builder.defineMacro("__wasm_fp16__"); + if (HasGC) + Builder.defineMacro("__wasm_gc__"); if (HasMultivalue) Builder.defineMacro("__wasm_multivalue__"); if (HasMutableGlobals) @@ -107,8 +109,6 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__wasm_nontrapping_fptoint__"); if (HasReferenceTypes) Builder.defineMacro("__wasm_reference_types__"); - if (HasGC) - Builder.defineMacro("__wasm_gc__"); if (SIMDLevel >= RelaxedSIMD) Builder.defineMacro("__wasm_relaxed_simd__"); if (HasSignExt) @@ -194,6 +194,7 @@ bool WebAssemblyTargetInfo::initFeatureMap( Features["exception-handling"] = true; Features["extended-const"] = true; Features["fp16"] = true; + Features["gc"] = true; Features["multimemory"] = true; Features["tail-call"] = true; Features["wide-arithmetic"] = true; @@ -270,6 +271,14 @@ bool WebAssemblyTargetInfo::handleTargetFeatures( HasFP16 = false; continue; } + if (Feature == "+gc") { + HasGC = true; + continue; + } + if (Feature == "-gc") { + HasGC = false; + continue; + } if (Feature == "+multimemory") { HasMultiMemory = true; continue; @@ -310,14 +319,6 @@ bool WebAssemblyTargetInfo::handleTargetFeatures( HasReferenceTypes = false; continue; } - if (Feature == "+gc") { - HasGC = true; - continue; - } - if (Feature == "-gc") { - HasGC = false; - continue; - } if (Feature == "+relaxed-simd") { SIMDLevel = std::max(SIMDLevel, RelaxedSIMD); continue; diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h index c47c8cc..eba7422 100644 --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -64,12 +64,12 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo { bool HasExceptionHandling = false; bool HasExtendedConst = false; bool HasFP16 = false; + bool HasGC = false; bool HasMultiMemory = false; bool HasMultivalue = false; bool HasMutableGlobals = false; bool HasNontrappingFPToInt = false; bool HasReferenceTypes = false; - bool HasGC = false; bool HasSignExt = false; bool HasTailCall = false; bool HasWideArithmetic = false; diff --git a/clang/lib/CIR/CodeGen/Address.h b/clang/lib/CIR/CodeGen/Address.h index 6f76c3e..6c927e9 100644 --- a/clang/lib/CIR/CodeGen/Address.h +++ b/clang/lib/CIR/CodeGen/Address.h @@ -101,6 +101,17 @@ public: } clang::CharUnits getAlignment() const { return alignment; } + + /// Get the operation which defines this address. + mlir::Operation *getDefiningOp() const { + if (!isValid()) + return nullptr; + return getPointer().getDefiningOp(); + } + + template <typename OpTy> OpTy getDefiningOp() const { + return mlir::dyn_cast_or_null<OpTy>(getDefiningOp()); + } }; } // namespace clang::CIRGen diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.h b/clang/lib/CIR/CodeGen/CIRGenCall.h index a78956b..28576a1 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.h +++ b/clang/lib/CIR/CodeGen/CIRGenCall.h @@ -137,7 +137,7 @@ private: /// A data-flow flag to make sure getRValue and/or copyInto are not /// called twice for duplicated IR emission. - mutable bool isUsed; + [[maybe_unused]] mutable bool isUsed; public: clang::QualType ty; diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index 50cca0e..72b9d17 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -349,12 +349,16 @@ void CIRGenFunction::emitCXXAggrConstructorCall( // doesn't happen, but it's not clear that it's worth it. // Optimize for a constant count. - auto constantCount = dyn_cast<cir::ConstantOp>(numElements.getDefiningOp()); - if (constantCount) { - auto constIntAttr = mlir::dyn_cast<cir::IntAttr>(constantCount.getValue()); - // Just skip out if the constant count is zero. - if (constIntAttr && constIntAttr.getUInt() == 0) - return; + if (auto constantCount = numElements.getDefiningOp<cir::ConstantOp>()) { + if (auto constIntAttr = constantCount.getValueAttr<cir::IntAttr>()) { + // Just skip out if the constant count is zero. + if (constIntAttr.getUInt() == 0) + return; + // Otherwise, emit the check. + } + + if (constantCount.use_empty()) + constantCount.erase(); } else { // Otherwise, emit the check. cgm.errorNYI(e->getSourceRange(), "dynamic-length array expression"); @@ -417,9 +421,6 @@ void CIRGenFunction::emitCXXAggrConstructorCall( builder.create<cir::YieldOp>(loc); }); } - - if (constantCount.use_empty()) - constantCount.erase(); } void CIRGenFunction::emitDelegateCXXConstructorCall( diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index 6527fb5..78d375c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -24,7 +24,8 @@ using namespace clang; using namespace clang::CIRGen; CIRGenFunction::AutoVarEmission -CIRGenFunction::emitAutoVarAlloca(const VarDecl &d) { +CIRGenFunction::emitAutoVarAlloca(const VarDecl &d, + mlir::OpBuilder::InsertPoint ip) { QualType ty = d.getType(); if (ty.getAddressSpace() != LangAS::Default) cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: address space"); @@ -50,7 +51,8 @@ CIRGenFunction::emitAutoVarAlloca(const VarDecl &d) { // A normal fixed sized variable becomes an alloca in the entry block, mlir::Type allocaTy = convertTypeForMem(ty); // Create the temp alloca and declare variable using it. - address = createTempAlloca(allocaTy, alignment, loc, d.getName()); + address = createTempAlloca(allocaTy, alignment, loc, d.getName(), + /*arraySize=*/nullptr, /*alloca=*/nullptr, ip); declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()), alignment); emission.Addr = address; @@ -156,7 +158,7 @@ void CIRGenFunction::emitAutoVarInit( // out of it while trying to build the expression, mark it as such. mlir::Value val = lv.getAddress().getPointer(); assert(val && "Should have an address"); - auto allocaOp = dyn_cast_or_null<cir::AllocaOp>(val.getDefiningOp()); + auto allocaOp = val.getDefiningOp<cir::AllocaOp>(); assert(allocaOp && "Address should come straight out of the alloca"); if (!allocaOp.use_empty()) @@ -410,7 +412,8 @@ void CIRGenFunction::emitStaticVarDecl(const VarDecl &d, // TODO(cir): we should have a way to represent global ops as values without // having to emit a get global op. Sometimes these emissions are not used. mlir::Value addr = builder.createGetGlobal(globalOp); - auto getAddrOp = mlir::cast<cir::GetGlobalOp>(addr.getDefiningOp()); + auto getAddrOp = addr.getDefiningOp<cir::GetGlobalOp>(); + assert(getAddrOp && "expected cir::GetGlobalOp"); CharUnits alignment = getContext().getDeclAlign(&d); @@ -520,7 +523,7 @@ void CIRGenFunction::emitExprAsInit(const Expr *init, const ValueDecl *d, llvm_unreachable("bad evaluation kind"); } -void CIRGenFunction::emitDecl(const Decl &d) { +void CIRGenFunction::emitDecl(const Decl &d, bool evaluateConditionDecl) { switch (d.getKind()) { case Decl::BuiltinTemplate: case Decl::TranslationUnit: @@ -608,11 +611,14 @@ void CIRGenFunction::emitDecl(const Decl &d) { case Decl::UsingDirective: // using namespace X; [C++] assert(!cir::MissingFeatures::generateDebugInfo()); return; - case Decl::Var: { + case Decl::Var: + case Decl::Decomposition: { const VarDecl &vd = cast<VarDecl>(d); assert(vd.isLocalVarDecl() && "Should not see file-scope variables inside a function!"); emitVarDecl(vd); + if (evaluateConditionDecl) + maybeEmitDeferredVarDeclInit(&vd); return; } case Decl::OpenACCDeclare: @@ -632,7 +638,6 @@ void CIRGenFunction::emitDecl(const Decl &d) { case Decl::ImplicitConceptSpecialization: case Decl::TopLevelStmt: case Decl::UsingPack: - case Decl::Decomposition: // This could be moved to join Decl::Var case Decl::OMPDeclareReduction: case Decl::OMPDeclareMapper: cgm.errorNYI(d.getSourceRange(), @@ -649,6 +654,27 @@ void CIRGenFunction::emitNullabilityCheck(LValue lhs, mlir::Value rhs, assert(!cir::MissingFeatures::sanitizers()); } +namespace { +struct DestroyObject final : EHScopeStack::Cleanup { + DestroyObject(Address addr, QualType type, + CIRGenFunction::Destroyer *destroyer) + : addr(addr), type(type), destroyer(destroyer) {} + + Address addr; + QualType type; + CIRGenFunction::Destroyer *destroyer; + + void emit(CIRGenFunction &cgf) override { + cgf.emitDestroy(addr, type, destroyer); + } +}; +} // namespace + +void CIRGenFunction::pushDestroy(CleanupKind cleanupKind, Address addr, + QualType type, Destroyer *destroyer) { + pushFullExprCleanup<DestroyObject>(cleanupKind, addr, type, destroyer); +} + /// Destroys all the elements of the given array, beginning from last to first. /// The array cannot be zero-length. /// @@ -736,22 +762,6 @@ CIRGenFunction::getDestroyer(QualType::DestructionKind kind) { llvm_unreachable("Unknown DestructionKind"); } -namespace { -struct DestroyObject final : EHScopeStack::Cleanup { - DestroyObject(Address addr, QualType type, - CIRGenFunction::Destroyer *destroyer) - : addr(addr), type(type), destroyer(destroyer) {} - - Address addr; - QualType type; - CIRGenFunction::Destroyer *destroyer; - - void emit(CIRGenFunction &cgf) override { - cgf.emitDestroy(addr, type, destroyer); - } -}; -} // namespace - /// Enter a destroy cleanup for the given local variable. void CIRGenFunction::emitAutoVarTypeCleanup( const CIRGenFunction::AutoVarEmission &emission, @@ -797,3 +807,11 @@ void CIRGenFunction::emitAutoVarTypeCleanup( assert(!cir::MissingFeatures::ehCleanupFlags()); ehStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer); } + +void CIRGenFunction::maybeEmitDeferredVarDeclInit(const VarDecl *vd) { + if (auto *dd = dyn_cast_if_present<DecompositionDecl>(vd)) { + for (auto *b : dd->flat_bindings()) + if (auto *hd = b->getHoldingVar()) + emitVarDecl(*hd); + } +} diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index c18498f..cd37a2b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -303,8 +303,7 @@ void CIRGenFunction::emitStoreOfScalar(mlir::Value value, Address addr, // Update the alloca with more info on initialization. assert(addr.getPointer() && "expected pointer to exist"); - auto srcAlloca = - dyn_cast_or_null<cir::AllocaOp>(addr.getPointer().getDefiningOp()); + auto srcAlloca = addr.getDefiningOp<cir::AllocaOp>(); if (currVarDecl && srcAlloca) { const VarDecl *vd = currVarDecl; assert(vd && "VarDecl expected"); @@ -584,6 +583,15 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) { return lv; } + if (const auto *bd = dyn_cast<BindingDecl>(nd)) { + if (e->refersToEnclosingVariableOrCapture()) { + assert(!cir::MissingFeatures::lambdaCaptures()); + cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: lambda captures"); + return LValue(); + } + return emitLValue(bd->getBinding()); + } + cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: unhandled decl type"); return LValue(); } @@ -626,10 +634,8 @@ LValue CIRGenFunction::emitUnaryOpLValue(const UnaryOperator *e) { // Tag 'load' with deref attribute. // FIXME: This misses some derefence cases and has problematic interactions // with other operators. - if (auto loadOp = - dyn_cast<cir::LoadOp>(addr.getPointer().getDefiningOp())) { + if (auto loadOp = addr.getDefiningOp<cir::LoadOp>()) loadOp.setIsDerefAttr(mlir::UnitAttr::get(&getMLIRContext())); - } LValue lv = makeAddrLValue(addr, t, baseInfo); assert(!cir::MissingFeatures::addressSpace()); @@ -712,8 +718,8 @@ static const Expr *getSimpleArrayDecayOperand(const Expr *e) { static cir::IntAttr getConstantIndexOrNull(mlir::Value idx) { // TODO(cir): should we consider using MLIRs IndexType instead of IntegerAttr? - if (auto constantOp = dyn_cast<cir::ConstantOp>(idx.getDefiningOp())) - return mlir::dyn_cast<cir::IntAttr>(constantOp.getValue()); + if (auto constantOp = idx.getDefiningOp<cir::ConstantOp>()) + return constantOp.getValueAttr<cir::IntAttr>(); return {}; } @@ -721,8 +727,7 @@ static CharUnits getArrayElementAlign(CharUnits arrayAlign, mlir::Value idx, CharUnits eltSize) { // If we have a constant index, we can use the exact offset of the // element we're accessing. - const cir::IntAttr constantIdx = getConstantIndexOrNull(idx); - if (constantIdx) { + if (const cir::IntAttr constantIdx = getConstantIndexOrNull(idx)) { const CharUnits offset = constantIdx.getValue().getZExtValue() * eltSize; return arrayAlign.alignmentAtOffset(offset); } @@ -1096,6 +1101,151 @@ void CIRGenFunction::emitAnyExprToMem(const Expr *e, Address location, llvm_unreachable("bad evaluation kind"); } +static Address createReferenceTemporary(CIRGenFunction &cgf, + const MaterializeTemporaryExpr *m, + const Expr *inner) { + // TODO(cir): cgf.getTargetHooks(); + switch (m->getStorageDuration()) { + case SD_FullExpression: + case SD_Automatic: { + QualType ty = inner->getType(); + + assert(!cir::MissingFeatures::mergeAllConstants()); + + // The temporary memory should be created in the same scope as the extending + // declaration of the temporary materialization expression. + cir::AllocaOp extDeclAlloca; + if (const ValueDecl *extDecl = m->getExtendingDecl()) { + auto extDeclAddrIter = cgf.localDeclMap.find(extDecl); + if (extDeclAddrIter != cgf.localDeclMap.end()) + extDeclAlloca = extDeclAddrIter->second.getDefiningOp<cir::AllocaOp>(); + } + mlir::OpBuilder::InsertPoint ip; + if (extDeclAlloca) + ip = {extDeclAlloca->getBlock(), extDeclAlloca->getIterator()}; + return cgf.createMemTemp(ty, cgf.getLoc(m->getSourceRange()), + cgf.getCounterRefTmpAsString(), /*alloca=*/nullptr, + ip); + } + case SD_Thread: + case SD_Static: { + cgf.cgm.errorNYI( + m->getSourceRange(), + "createReferenceTemporary: static/thread storage duration"); + return Address::invalid(); + } + + case SD_Dynamic: + llvm_unreachable("temporary can't have dynamic storage duration"); + } + llvm_unreachable("unknown storage duration"); +} + +static void pushTemporaryCleanup(CIRGenFunction &cgf, + const MaterializeTemporaryExpr *m, + const Expr *e, Address referenceTemporary) { + // Objective-C++ ARC: + // If we are binding a reference to a temporary that has ownership, we + // need to perform retain/release operations on the temporary. + // + // FIXME(ogcg): This should be looking at e, not m. + if (m->getType().getObjCLifetime()) { + cgf.cgm.errorNYI(e->getSourceRange(), "pushTemporaryCleanup: ObjCLifetime"); + return; + } + + CXXDestructorDecl *referenceTemporaryDtor = nullptr; + if (const clang::RecordType *rt = e->getType() + ->getBaseElementTypeUnsafe() + ->getAs<clang::RecordType>()) { + // Get the destructor for the reference temporary. + auto *classDecl = cast<CXXRecordDecl>(rt->getDecl()); + if (!classDecl->hasTrivialDestructor()) + referenceTemporaryDtor = classDecl->getDestructor(); + } + + if (!referenceTemporaryDtor) + return; + + // Call the destructor for the temporary. + switch (m->getStorageDuration()) { + case SD_Static: + case SD_Thread: + cgf.cgm.errorNYI(e->getSourceRange(), + "pushTemporaryCleanup: static/thread storage duration"); + return; + + case SD_FullExpression: + cgf.pushDestroy(NormalAndEHCleanup, referenceTemporary, e->getType(), + CIRGenFunction::destroyCXXObject); + break; + + case SD_Automatic: + cgf.cgm.errorNYI(e->getSourceRange(), + "pushTemporaryCleanup: automatic storage duration"); + break; + + case SD_Dynamic: + llvm_unreachable("temporary cannot have dynamic storage duration"); + } +} + +LValue CIRGenFunction::emitMaterializeTemporaryExpr( + const MaterializeTemporaryExpr *m) { + const Expr *e = m->getSubExpr(); + + assert((!m->getExtendingDecl() || !isa<VarDecl>(m->getExtendingDecl()) || + !cast<VarDecl>(m->getExtendingDecl())->isARCPseudoStrong()) && + "Reference should never be pseudo-strong!"); + + // FIXME: ideally this would use emitAnyExprToMem, however, we cannot do so + // as that will cause the lifetime adjustment to be lost for ARC + auto ownership = m->getType().getObjCLifetime(); + if (ownership != Qualifiers::OCL_None && + ownership != Qualifiers::OCL_ExplicitNone) { + cgm.errorNYI(e->getSourceRange(), + "emitMaterializeTemporaryExpr: ObjCLifetime"); + return {}; + } + + SmallVector<const Expr *, 2> commaLHSs; + SmallVector<SubobjectAdjustment, 2> adjustments; + e = e->skipRValueSubobjectAdjustments(commaLHSs, adjustments); + + for (const Expr *ignored : commaLHSs) + emitIgnoredExpr(ignored); + + if (isa<OpaqueValueExpr>(e)) { + cgm.errorNYI(e->getSourceRange(), + "emitMaterializeTemporaryExpr: OpaqueValueExpr"); + return {}; + } + + // Create and initialize the reference temporary. + Address object = createReferenceTemporary(*this, m, e); + + if (auto var = object.getPointer().getDefiningOp<cir::GlobalOp>()) { + // TODO(cir): add something akin to stripPointerCasts() to ptr above + cgm.errorNYI(e->getSourceRange(), "emitMaterializeTemporaryExpr: GlobalOp"); + return {}; + } else { + assert(!cir::MissingFeatures::emitLifetimeMarkers()); + emitAnyExprToMem(e, object, Qualifiers(), /*isInitializer=*/true); + } + pushTemporaryCleanup(*this, m, e, object); + + // Perform derived-to-base casts and/or field accesses, to get from the + // temporary object we created (and, potentially, for which we extended + // the lifetime) to the subobject we're binding the reference to. + if (!adjustments.empty()) { + cgm.errorNYI(e->getSourceRange(), + "emitMaterializeTemporaryExpr: Adjustments"); + return {}; + } + + return makeAddrLValue(object, m->getType(), AlignmentSource::Decl); +} + LValue CIRGenFunction::emitCompoundLiteralLValue(const CompoundLiteralExpr *e) { if (e->isFileScope()) { cgm.errorNYI(e->getSourceRange(), "emitCompoundLiteralLValue: FileScope"); @@ -1472,9 +1622,10 @@ Address CIRGenFunction::emitArrayToPointerDecay(const Expr *e) { if (e->getType()->isVariableArrayType()) return addr; - auto pointeeTy = mlir::cast<cir::ArrayType>(lvalueAddrTy.getPointee()); + [[maybe_unused]] auto pointeeTy = + mlir::cast<cir::ArrayType>(lvalueAddrTy.getPointee()); - mlir::Type arrayTy = convertType(e->getType()); + [[maybe_unused]] mlir::Type arrayTy = convertType(e->getType()); assert(mlir::isa<cir::ArrayType>(arrayTy) && "expected array"); assert(pointeeTy == arrayTy); @@ -1852,9 +2003,9 @@ cir::AllocaOp CIRGenFunction::createTempAlloca(mlir::Type ty, const Twine &name, mlir::Value arraySize, bool insertIntoFnEntryBlock) { - return cast<cir::AllocaOp>(emitAlloca(name.str(), ty, loc, CharUnits(), - insertIntoFnEntryBlock, arraySize) - .getDefiningOp()); + return mlir::cast<cir::AllocaOp>(emitAlloca(name.str(), ty, loc, CharUnits(), + insertIntoFnEntryBlock, arraySize) + .getDefiningOp()); } /// This creates an alloca and inserts it into the provided insertion point @@ -1864,7 +2015,7 @@ cir::AllocaOp CIRGenFunction::createTempAlloca(mlir::Type ty, mlir::OpBuilder::InsertPoint ip, mlir::Value arraySize) { assert(ip.isSet() && "Insertion point is not set"); - return cast<cir::AllocaOp>( + return mlir::cast<cir::AllocaOp>( emitAlloca(name.str(), ty, loc, CharUnits(), ip, arraySize) .getDefiningOp()); } diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp index a09d739..3aa170e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp @@ -91,6 +91,14 @@ public: } mlir::Value VisitUnaryDeref(const Expr *e); + + mlir::Value VisitUnaryPlus(const UnaryOperator *e); + + mlir::Value VisitPlusMinus(const UnaryOperator *e, cir::UnaryOpKind kind, + QualType promotionType); + + mlir::Value VisitUnaryMinus(const UnaryOperator *e); + mlir::Value VisitUnaryNot(const UnaryOperator *e); struct BinOpInfo { @@ -110,6 +118,7 @@ public: mlir::Value emitBinAdd(const BinOpInfo &op); mlir::Value emitBinSub(const BinOpInfo &op); + mlir::Value emitBinMul(const BinOpInfo &op); QualType getPromotionType(QualType ty, bool isDivOpCode = false) { if (auto *complexTy = ty->getAs<ComplexType>()) { @@ -142,16 +151,20 @@ public: HANDLEBINOP(Add) HANDLEBINOP(Sub) + HANDLEBINOP(Mul) #undef HANDLEBINOP }; } // namespace +#ifndef NDEBUG +// Only used in asserts static const ComplexType *getComplexType(QualType type) { type = type.getCanonicalType(); if (const ComplexType *comp = dyn_cast<ComplexType>(type)) return comp; return cast<ComplexType>(cast<AtomicType>(type)->getValueType()); } +#endif // NDEBUG LValue ComplexExprEmitter::emitBinAssignLValue(const BinaryOperator *e, mlir::Value &value) { @@ -282,6 +295,41 @@ mlir::Value ComplexExprEmitter::emitCast(CastKind ck, Expr *op, llvm_unreachable("unknown cast resulting in complex value"); } +mlir::Value ComplexExprEmitter::VisitUnaryPlus(const UnaryOperator *e) { + QualType promotionTy = getPromotionType(e->getSubExpr()->getType()); + mlir::Value result = VisitPlusMinus(e, cir::UnaryOpKind::Plus, promotionTy); + if (!promotionTy.isNull()) { + cgf.cgm.errorNYI("ComplexExprEmitter::VisitUnaryPlus emitUnPromotedValue"); + return {}; + } + return result; +} + +mlir::Value ComplexExprEmitter::VisitPlusMinus(const UnaryOperator *e, + cir::UnaryOpKind kind, + QualType promotionType) { + assert(kind == cir::UnaryOpKind::Plus || + kind == cir::UnaryOpKind::Minus && + "Invalid UnaryOp kind for ComplexType Plus or Minus"); + + mlir::Value op; + if (!promotionType.isNull()) + op = cgf.emitPromotedComplexExpr(e->getSubExpr(), promotionType); + else + op = Visit(e->getSubExpr()); + return builder.createUnaryOp(cgf.getLoc(e->getExprLoc()), kind, op); +} + +mlir::Value ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *e) { + QualType promotionTy = getPromotionType(e->getSubExpr()->getType()); + mlir::Value result = VisitPlusMinus(e, cir::UnaryOpKind::Minus, promotionTy); + if (!promotionTy.isNull()) { + cgf.cgm.errorNYI("ComplexExprEmitter::VisitUnaryMinus emitUnPromotedValue"); + return {}; + } + return result; +} + mlir::Value ComplexExprEmitter::emitConstant( const CIRGenFunction::ConstantEmission &constant, Expr *e) { assert(constant && "not a constant"); @@ -534,13 +582,22 @@ mlir::Value ComplexExprEmitter::emitPromoted(const Expr *e, return emitBin##OP(emitBinOps(bo, promotionTy)); HANDLE_BINOP(Add) HANDLE_BINOP(Sub) + HANDLE_BINOP(Mul) #undef HANDLE_BINOP default: break; } - } else if (isa<UnaryOperator>(e)) { - cgf.cgm.errorNYI("emitPromoted UnaryOperator"); - return {}; + } else if (const auto *unaryOp = dyn_cast<UnaryOperator>(e)) { + switch (unaryOp->getOpcode()) { + case UO_Minus: + case UO_Plus: { + auto kind = unaryOp->getOpcode() == UO_Plus ? cir::UnaryOpKind::Plus + : cir::UnaryOpKind::Minus; + return VisitPlusMinus(unaryOp, kind, promotionTy); + } + default: + break; + } } mlir::Value result = Visit(const_cast<Expr *>(e)); @@ -585,6 +642,31 @@ mlir::Value ComplexExprEmitter::emitBinSub(const BinOpInfo &op) { return builder.create<cir::ComplexSubOp>(op.loc, op.lhs, op.rhs); } +static cir::ComplexRangeKind +getComplexRangeAttr(LangOptions::ComplexRangeKind range) { + switch (range) { + case LangOptions::CX_Full: + return cir::ComplexRangeKind::Full; + case LangOptions::CX_Improved: + return cir::ComplexRangeKind::Improved; + case LangOptions::CX_Promoted: + return cir::ComplexRangeKind::Promoted; + case LangOptions::CX_Basic: + return cir::ComplexRangeKind::Basic; + case LangOptions::CX_None: + // The default value for ComplexRangeKind is Full is no option is selected + return cir::ComplexRangeKind::Full; + } +} + +mlir::Value ComplexExprEmitter::emitBinMul(const BinOpInfo &op) { + assert(!cir::MissingFeatures::fastMathFlags()); + assert(!cir::MissingFeatures::cgFPOptionsRAII()); + cir::ComplexRangeKind rangeKind = + getComplexRangeAttr(op.fpFeatures.getComplexRange()); + return builder.create<cir::ComplexMulOp>(op.loc, op.lhs, op.rhs, rangeKind); +} + LValue CIRGenFunction::emitComplexAssignmentLValue(const BinaryOperator *e) { assert(e->getOpcode() == BO_Assign && "Expected assign op"); diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 2523b0f..32c1c1a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -48,8 +48,8 @@ struct BinOpInfo { /// Check if the binop can result in integer overflow. bool mayHaveIntegerOverflow() const { // Without constant input, we can't rule out overflow. - auto lhsci = dyn_cast<cir::ConstantOp>(lhs.getDefiningOp()); - auto rhsci = dyn_cast<cir::ConstantOp>(rhs.getDefiningOp()); + auto lhsci = lhs.getDefiningOp<cir::ConstantOp>(); + auto rhsci = rhs.getDefiningOp<cir::ConstantOp>(); if (!lhsci || !rhsci) return true; @@ -439,7 +439,7 @@ public: value = builder.getTrue(cgf.getLoc(e->getExprLoc())); } else if (type->isIntegerType()) { QualType promotedType; - bool canPerformLossyDemotionCheck = false; + [[maybe_unused]] bool canPerformLossyDemotionCheck = false; if (cgf.getContext().isPromotableIntegerType(type)) { promotedType = cgf.getContext().getPromotedIntegerType(type); assert(promotedType != type && "Shouldn't promote to the same type."); @@ -626,6 +626,7 @@ public: mlir::Value VisitCXXThisExpr(CXXThisExpr *te) { return cgf.loadCXXThis(); } + mlir::Value VisitExprWithCleanups(ExprWithCleanups *e); mlir::Value VisitCXXNewExpr(const CXXNewExpr *e) { return cgf.emitCXXNewExpr(e); } @@ -1217,6 +1218,29 @@ mlir::Value ScalarExprEmitter::emitCompoundAssign( return emitLoadOfLValue(lhs, e->getExprLoc()); } +mlir::Value ScalarExprEmitter::VisitExprWithCleanups(ExprWithCleanups *e) { + mlir::Location scopeLoc = cgf.getLoc(e->getSourceRange()); + mlir::OpBuilder &builder = cgf.builder; + + auto scope = cir::ScopeOp::create( + builder, scopeLoc, + /*scopeBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Type &yieldTy, mlir::Location loc) { + CIRGenFunction::LexicalScope lexScope{cgf, loc, + builder.getInsertionBlock()}; + mlir::Value scopeYieldVal = Visit(e->getSubExpr()); + if (scopeYieldVal) { + // Defend against dominance problems caused by jumps out of expression + // evaluation through the shared cleanup block. + lexScope.forceCleanup(); + cir::YieldOp::create(builder, loc, scopeYieldVal); + yieldTy = scopeYieldVal.getType(); + } + }); + + return scope.getNumResults() > 0 ? scope->getResult(0) : nullptr; +} + } // namespace LValue diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index c65d025..f8e7347 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -216,11 +216,12 @@ void CIRGenFunction::emitAndUpdateRetAlloca(QualType type, mlir::Location loc, void CIRGenFunction::declare(mlir::Value addrVal, const Decl *var, QualType ty, mlir::Location loc, CharUnits alignment, bool isParam) { - const auto *namedVar = dyn_cast_or_null<NamedDecl>(var); - assert(namedVar && "Needs a named decl"); + assert(isa<NamedDecl>(var) && "Needs a named decl"); assert(!cir::MissingFeatures::cgfSymbolTable()); - auto allocaOp = cast<cir::AllocaOp>(addrVal.getDefiningOp()); + auto allocaOp = addrVal.getDefiningOp<cir::AllocaOp>(); + assert(allocaOp && "expected cir::AllocaOp"); + if (isParam) allocaOp.setInitAttr(mlir::UnitAttr::get(&getMLIRContext())); if (ty->isReferenceType() || ty.isConstQualified()) @@ -801,6 +802,8 @@ LValue CIRGenFunction::emitLValue(const Expr *e) { case Expr::CXXDynamicCastExprClass: case Expr::ImplicitCastExprClass: return emitCastLValue(cast<CastExpr>(e)); + case Expr::MaterializeTemporaryExprClass: + return emitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(e)); } } @@ -811,6 +814,10 @@ static std::string getVersionedTmpName(llvm::StringRef name, unsigned cnt) { return std::string(out.str()); } +std::string CIRGenFunction::getCounterRefTmpAsString() { + return getVersionedTmpName("ref.tmp", counterRefTmp++); +} + std::string CIRGenFunction::getCounterAggTmpAsString() { return getVersionedTmpName("agg.tmp", counterAggTmp++); } @@ -943,6 +950,7 @@ void CIRGenFunction::emitVariablyModifiedType(QualType type) { case Type::HLSLInlineSpirv: case Type::PredefinedSugar: cgm.errorNYI("CIRGenFunction::emitVariablyModifiedType"); + break; #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 603f750..68d54bb 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -325,7 +325,9 @@ public: }; /// Hold counters for incrementally naming temporaries + unsigned counterRefTmp = 0; unsigned counterAggTmp = 0; + std::string getCounterRefTmpAsString(); std::string getCounterAggTmpAsString(); /// Helpers to convert Clang's SourceLocation to a MLIR Location. @@ -604,6 +606,19 @@ public: void popCleanupBlocks(size_t oldCleanupStackDepth); void popCleanupBlock(); + /// Push a cleanup to be run at the end of the current full-expression. Safe + /// against the possibility that we're currently inside a + /// conditionally-evaluated expression. + template <class T, class... As> + void pushFullExprCleanup(CleanupKind kind, As... a) { + // If we're not in a conditional branch, or if none of the + // arguments requires saving, then use the unconditional cleanup. + if (!isInConditionalBranch()) + return ehStack.pushCleanup<T>(kind, a...); + + cgm.errorNYI("pushFullExprCleanup in conditional branch"); + } + /// Enters a new scope for capturing cleanups, all of which /// will be executed once the scope is exited. class RunCleanupsScope { @@ -619,6 +634,7 @@ public: protected: CIRGenFunction &cgf; + public: /// Enter a new cleanup scope. explicit RunCleanupsScope(CIRGenFunction &cgf) : performCleanup(true), cgf(cgf) { @@ -801,6 +817,9 @@ public: static Destroyer destroyCXXObject; + void pushDestroy(CleanupKind kind, Address addr, QualType type, + Destroyer *destroyer); + Destroyer *getDestroyer(clang::QualType::DestructionKind kind); /// ---------------------- @@ -858,7 +877,8 @@ public: Address emitArrayToPointerDecay(const Expr *array); - AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d); + AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d, + mlir::OpBuilder::InsertPoint ip = {}); /// Emit code and set up symbol table for a variable declaration with auto, /// register, or no storage class specifier. These turn into simple stack @@ -870,6 +890,8 @@ public: void emitAutoVarTypeCleanup(const AutoVarEmission &emission, clang::QualType::DestructionKind dtorKind); + void maybeEmitDeferredVarDeclInit(const VarDecl *vd); + void emitBaseInitializer(mlir::Location loc, const CXXRecordDecl *classDecl, CXXCtorInitializer *baseInit); @@ -1059,7 +1081,7 @@ public: void emitCompoundStmtWithoutScope(const clang::CompoundStmt &s); - void emitDecl(const clang::Decl &d); + void emitDecl(const clang::Decl &d, bool evaluateConditionDecl = false); mlir::LogicalResult emitDeclStmt(const clang::DeclStmt &s); LValue emitDeclRefLValue(const clang::DeclRefExpr *e); @@ -1136,6 +1158,8 @@ public: const clang::FieldDecl *field, llvm::StringRef fieldName); + LValue emitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *e); + LValue emitMemberExpr(const MemberExpr *e); /// Given an expression with a pointer type, emit the value and compute our @@ -1375,6 +1399,7 @@ public: mlir::Location beginLoc; mlir::Value varValue; std::string name; + QualType baseType; llvm::SmallVector<mlir::Value> bounds; }; // Gets the collection of info required to lower and OpenACC clause or cache diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 623b84f..b143682 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -656,8 +656,6 @@ mlir::Value CIRGenModule::getAddrOfGlobalVar(const VarDecl *d, mlir::Type ty, void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd, bool isTentative) { - const QualType astTy = vd->getType(); - if (getLangOpts().OpenCL || getLangOpts().OpenMPIsTargetDevice) { errorNYI(vd->getSourceRange(), "emit OpenCL/OpenMP global variable"); return; @@ -701,7 +699,7 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd, // never attempt to emit a tentative definition if a real one // exists. A use may still exists, however, so we still may need // to do a RAUW. - assert(!astTy->isIncompleteType() && "Unexpected incomplete type"); + assert(!vd->getType()->isIncompleteType() && "Unexpected incomplete type"); init = builder.getZeroInitAttr(convertType(vd->getType())); } else { emitter.emplace(*this); @@ -1308,8 +1306,13 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) { break; } - case Decl::Var: { + case Decl::Var: + case Decl::Decomposition: { auto *vd = cast<VarDecl>(decl); + if (isa<DecompositionDecl>(decl)) { + errorNYI(decl->getSourceRange(), "global variable decompositions"); + break; + } emitGlobal(vd); break; } @@ -1331,8 +1334,14 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) { break; // No code generation needed. - case Decl::UsingShadow: + case Decl::ClassTemplate: + case Decl::Concept: + case Decl::CXXDeductionGuide: case Decl::Empty: + case Decl::FunctionTemplate: + case Decl::StaticAssert: + case Decl::TypeAliasTemplate: + case Decl::UsingShadow: break; case Decl::CXXConstructor: diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp index 49ff124..32095cb 100644 --- a/clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp @@ -119,7 +119,7 @@ CIRGenFunction::getOpenACCDataOperandInfo(const Expr *e) { if (const auto *memExpr = dyn_cast<MemberExpr>(curVarExpr)) return {exprLoc, emitMemberExpr(memExpr).getPointer(), exprString, - std::move(bounds)}; + curVarExpr->getType(), std::move(bounds)}; // Sema has made sure that only 4 types of things can get here, array // subscript, array section, member expr, or DRE to a var decl (or the @@ -127,5 +127,5 @@ CIRGenFunction::getOpenACCDataOperandInfo(const Expr *e) { // right. const auto *dre = cast<DeclRefExpr>(curVarExpr); return {exprLoc, emitDeclRefLValue(dre).getPointer(), exprString, - std::move(bounds)}; + curVarExpr->getType(), std::move(bounds)}; } diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp index e45d3b8f..5a6e665 100644 --- a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp @@ -12,6 +12,7 @@ #include <type_traits> +#include "CIRGenCXXABI.h" #include "CIRGenFunction.h" #include "clang/AST/ExprCXX.h" @@ -355,6 +356,110 @@ class OpenACCClauseCIREmitter final } } + template <typename RecipeTy> + RecipeTy getOrCreateRecipe(ASTContext &astCtx, const Expr *varRef, + DeclContext *dc, QualType baseType, + mlir::Value mainOp) { + mlir::ModuleOp mod = + builder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>(); + + std::string recipeName; + { + llvm::raw_string_ostream stream(recipeName); + if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) { + stream << "privatization_"; + } else if constexpr (std::is_same_v<RecipeTy, + mlir::acc::FirstprivateRecipeOp>) { + stream << "firstprivatization_"; + + } else if constexpr (std::is_same_v<RecipeTy, + mlir::acc::ReductionRecipeOp>) { + stream << "reduction_"; + // We don't have the reduction operation here well enough to know how to + // spell this correctly (+ == 'add', etc), so when we implement + // 'reduction' we have to do that here. + cgf.cgm.errorNYI(varRef->getSourceRange(), + "OpeNACC reduction recipe creation"); + } else { + static_assert(!sizeof(RecipeTy), "Unknown Recipe op kind"); + } + + MangleContext &mc = cgf.cgm.getCXXABI().getMangleContext(); + mc.mangleCanonicalTypeName(baseType, stream); + } + + if (auto recipe = mod.lookupSymbol<RecipeTy>(recipeName)) + return recipe; + + mlir::Location loc = cgf.cgm.getLoc(varRef->getBeginLoc()); + mlir::Location locEnd = cgf.cgm.getLoc(varRef->getEndLoc()); + + mlir::OpBuilder modBuilder(mod.getBodyRegion()); + auto recipe = + RecipeTy::create(modBuilder, loc, recipeName, mainOp.getType()); + + // Magic-up a var-decl so we can use normal init/destruction operations for + // a variable declaration. + VarDecl &tempDecl = *VarDecl::Create( + astCtx, dc, varRef->getBeginLoc(), varRef->getBeginLoc(), + &astCtx.Idents.get("openacc.private.init"), baseType, + astCtx.getTrivialTypeSourceInfo(baseType), SC_Auto); + CIRGenFunction::AutoVarEmission tempDeclEmission{ + CIRGenFunction::AutoVarEmission::invalid()}; + + // Init section. + { + llvm::SmallVector<mlir::Type> argsTys{mainOp.getType()}; + llvm::SmallVector<mlir::Location> argsLocs{loc}; + builder.createBlock(&recipe.getInitRegion(), recipe.getInitRegion().end(), + argsTys, argsLocs); + builder.setInsertionPointToEnd(&recipe.getInitRegion().back()); + + if constexpr (!std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) { + // We have only implemented 'init' for private, so make this NYI until + // we have explicitly implemented everything. + cgf.cgm.errorNYI(varRef->getSourceRange(), + "OpenACC non-private recipe init"); + } + + tempDeclEmission = + cgf.emitAutoVarAlloca(tempDecl, builder.saveInsertionPoint()); + cgf.emitAutoVarInit(tempDeclEmission); + + mlir::acc::YieldOp::create(builder, locEnd); + } + + // Copy section. + if constexpr (std::is_same_v<RecipeTy, mlir::acc::FirstprivateRecipeOp> || + std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) { + // TODO: OpenACC: 'private' doesn't emit this, but for the other two we + // have to figure out what 'copy' means here. + cgf.cgm.errorNYI(varRef->getSourceRange(), + "OpenACC record type privatization copy section"); + } + + // Destroy section (doesn't currently exist). + if (tempDecl.needsDestruction(cgf.getContext())) { + llvm::SmallVector<mlir::Type> argsTys{mainOp.getType()}; + llvm::SmallVector<mlir::Location> argsLocs{loc}; + mlir::Block *block = builder.createBlock(&recipe.getDestroyRegion(), + recipe.getDestroyRegion().end(), + argsTys, argsLocs); + builder.setInsertionPointToEnd(&recipe.getDestroyRegion().back()); + + mlir::Type elementTy = + mlir::cast<cir::PointerType>(mainOp.getType()).getPointee(); + Address addr{block->getArgument(0), elementTy, + cgf.getContext().getDeclAlign(&tempDecl)}; + cgf.emitDestroy(addr, baseType, + cgf.getDestroyer(QualType::DK_cxx_destructor)); + + mlir::acc::YieldOp::create(builder, locEnd); + } + + return recipe; + } + public: OpenACCClauseCIREmitter(OpTy &operation, CIRGen::CIRGenFunction &cgf, CIRGen::CIRGenBuilderTy &builder, @@ -971,6 +1076,37 @@ public: llvm_unreachable("Unknown construct kind in VisitAttachClause"); } } + + void VisitPrivateClause(const OpenACCPrivateClause &clause) { + if constexpr (isOneOfTypes<OpTy, mlir::acc::ParallelOp, mlir::acc::SerialOp, + mlir::acc::LoopOp>) { + for (const Expr *var : clause.getVarList()) { + CIRGenFunction::OpenACCDataOperandInfo opInfo = + cgf.getOpenACCDataOperandInfo(var); + auto privateOp = mlir::acc::PrivateOp::create( + builder, opInfo.beginLoc, opInfo.varValue, /*structured=*/true, + /*implicit=*/false, opInfo.name, opInfo.bounds); + privateOp.setDataClause(mlir::acc::DataClause::acc_private); + + { + mlir::OpBuilder::InsertionGuard guardCase(builder); + auto recipe = getOrCreateRecipe<mlir::acc::PrivateRecipeOp>( + cgf.getContext(), var, Decl::castToDeclContext(cgf.curFuncDecl), + opInfo.baseType, privateOp.getResult()); + // TODO: OpenACC: The dialect is going to change in the near future to + // have these be on a different operation, so when that changes, we + // probably need to change these here. + operation.addPrivatization(builder.getContext(), privateOp, recipe); + } + } + } else if constexpr (isCombinedType<OpTy>) { + // Despite this being valid on ParallelOp or SerialOp, combined type + // applies to the 'loop'. + applyToLoopOp(clause); + } else { + llvm_unreachable("Unknown construct kind in VisitPrivateClause"); + } + } }; template <typename OpTy> diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp index e4ec380..ecf31a7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp @@ -41,7 +41,7 @@ struct CIRRecordLowering final { // member type that ensures correct rounding. struct MemberInfo final { CharUnits offset; - enum class InfoKind { Field, Base } kind; + enum class InfoKind { VFPtr, Field, Base } kind; mlir::Type data; union { const FieldDecl *fieldDecl; @@ -87,10 +87,15 @@ struct CIRRecordLowering final { accumulateBitFields(RecordDecl::field_iterator field, RecordDecl::field_iterator fieldEnd); + mlir::Type getVFPtrType(); + bool isAAPCS() const { return astContext.getTargetInfo().getABI().starts_with("aapcs"); } + /// Helper function to check if the target machine is BigEndian. + bool isBigEndian() const { return astContext.getTargetInfo().isBigEndian(); } + CharUnits bitsToCharUnits(uint64_t bitOffset) { return astContext.toCharUnitsFromBits(bitOffset); } @@ -496,11 +501,7 @@ void CIRRecordLowering::accumulateFields() { fieldEnd = recordDecl->field_end(); field != fieldEnd;) { if (field->isBitField()) { - RecordDecl::field_iterator start = field; - // Iterate to gather the list of bitfields. - for (++field; field != fieldEnd && field->isBitField(); ++field) - ; - field = accumulateBitFields(start, field); + field = accumulateBitFields(field, fieldEnd); assert((field == fieldEnd || !field->isBitField()) && "Failed to accumulate all the bitfields"); } else if (!field->isZeroSize(astContext)) { @@ -771,7 +772,104 @@ void CIRRecordLowering::computeVolatileBitfields() { !cirGenTypes.getCGModule().getCodeGenOpts().AAPCSBitfieldWidth) return; - assert(!cir::MissingFeatures::armComputeVolatileBitfields()); + for (auto &[field, info] : bitFields) { + mlir::Type resLTy = cirGenTypes.convertTypeForMem(field->getType()); + + if (astContext.toBits(astRecordLayout.getAlignment()) < + getSizeInBits(resLTy).getQuantity()) + continue; + + // CIRRecordLowering::setBitFieldInfo() pre-adjusts the bit-field offsets + // for big-endian targets, but it assumes a container of width + // info.storageSize. Since AAPCS uses a different container size (width + // of the type), we first undo that calculation here and redo it once + // the bit-field offset within the new container is calculated. + const unsigned oldOffset = + isBigEndian() ? info.storageSize - (info.offset + info.size) + : info.offset; + // Offset to the bit-field from the beginning of the struct. + const unsigned absoluteOffset = + astContext.toBits(info.storageOffset) + oldOffset; + + // Container size is the width of the bit-field type. + const unsigned storageSize = getSizeInBits(resLTy).getQuantity(); + // Nothing to do if the access uses the desired + // container width and is naturally aligned. + if (info.storageSize == storageSize && (oldOffset % storageSize == 0)) + continue; + + // Offset within the container. + unsigned offset = absoluteOffset & (storageSize - 1); + // Bail out if an aligned load of the container cannot cover the entire + // bit-field. This can happen for example, if the bit-field is part of a + // packed struct. AAPCS does not define access rules for such cases, we let + // clang to follow its own rules. + if (offset + info.size > storageSize) + continue; + + // Re-adjust offsets for big-endian targets. + if (isBigEndian()) + offset = storageSize - (offset + info.size); + + const CharUnits storageOffset = + astContext.toCharUnitsFromBits(absoluteOffset & ~(storageSize - 1)); + const CharUnits end = storageOffset + + astContext.toCharUnitsFromBits(storageSize) - + CharUnits::One(); + + const ASTRecordLayout &layout = + astContext.getASTRecordLayout(field->getParent()); + // If we access outside memory outside the record, than bail out. + const CharUnits recordSize = layout.getSize(); + if (end >= recordSize) + continue; + + // Bail out if performing this load would access non-bit-fields members. + bool conflict = false; + for (const auto *f : recordDecl->fields()) { + // Allow sized bit-fields overlaps. + if (f->isBitField() && !f->isZeroLengthBitField()) + continue; + + const CharUnits fOffset = astContext.toCharUnitsFromBits( + layout.getFieldOffset(f->getFieldIndex())); + + // As C11 defines, a zero sized bit-field defines a barrier, so + // fields after and before it should be race condition free. + // The AAPCS acknowledges it and imposes no restritions when the + // natural container overlaps a zero-length bit-field. + if (f->isZeroLengthBitField()) { + if (end > fOffset && storageOffset < fOffset) { + conflict = true; + break; + } + } + + const CharUnits fEnd = + fOffset + + astContext.toCharUnitsFromBits(astContext.toBits( + getSizeInBits(cirGenTypes.convertTypeForMem(f->getType())))) - + CharUnits::One(); + // If no overlap, continue. + if (end < fOffset || fEnd < storageOffset) + continue; + + // The desired load overlaps a non-bit-field member, bail out. + conflict = true; + break; + } + + if (conflict) + continue; + // Write the new bit-field access parameters. + // As the storage offset now is defined as the number of elements from the + // start of the structure, we should divide the Offset by the element size. + info.volatileStorageOffset = + storageOffset / + astContext.toCharUnitsFromBits(storageSize).getQuantity(); + info.volatileStorageSize = storageSize; + info.volatileOffset = offset; + } } void CIRRecordLowering::accumulateBases(const CXXRecordDecl *cxxRecordDecl) { @@ -802,9 +900,14 @@ void CIRRecordLowering::accumulateBases(const CXXRecordDecl *cxxRecordDecl) { void CIRRecordLowering::accumulateVPtrs() { if (astRecordLayout.hasOwnVFPtr()) - cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(), - "accumulateVPtrs: hasOwnVFPtr"); + members.push_back(MemberInfo(CharUnits::Zero(), MemberInfo::InfoKind::VFPtr, + getVFPtrType())); + if (astRecordLayout.hasOwnVBPtr()) cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(), "accumulateVPtrs: hasOwnVBPtr"); } + +mlir::Type CIRRecordLowering::getVFPtrType() { + return cir::VPtrType::get(builder.getContext()); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp index 21bee33..50642e7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp @@ -79,14 +79,15 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s, #define EXPR(Type, Base) case Stmt::Type##Class: #include "clang/AST/StmtNodes.inc" { - // Remember the block we came in on. - mlir::Block *incoming = builder.getInsertionBlock(); - assert(incoming && "expression emission must have an insertion point"); + assert(builder.getInsertionBlock() && + "expression emission must have an insertion point"); emitIgnoredExpr(cast<Expr>(s)); - mlir::Block *outgoing = builder.getInsertionBlock(); - assert(outgoing && "expression emission cleared block!"); + // Classic codegen has a check here to see if the emitter created a new + // block that isn't used (comparing the incoming and outgoing insertion + // points) and deletes the outgoing block if it's not used. In CIR, we + // will handle that during the cir.canonicalize pass. return mlir::success(); } case Stmt::IfStmtClass: @@ -363,8 +364,8 @@ mlir::LogicalResult CIRGenFunction::emitIfStmt(const IfStmt &s) { mlir::LogicalResult CIRGenFunction::emitDeclStmt(const DeclStmt &s) { assert(builder.getInsertionBlock() && "expected valid insertion point"); - for (const Decl *I : s.decls()) - emitDecl(*I); + for (const Decl *i : s.decls()) + emitDecl(*i, /*evaluateConditionDecl=*/true); return mlir::success(); } @@ -875,7 +876,7 @@ mlir::LogicalResult CIRGenFunction::emitSwitchStmt(const clang::SwitchStmt &s) { return mlir::failure(); if (s.getConditionVariable()) - emitDecl(*s.getConditionVariable()); + emitDecl(*s.getConditionVariable(), /*evaluateConditionDecl=*/true); mlir::Value condV = emitScalarExpr(s.getCond()); diff --git a/clang/lib/CIR/CodeGen/CIRGenerator.cpp b/clang/lib/CIR/CodeGen/CIRGenerator.cpp index 99d6528..b0357d9 100644 --- a/clang/lib/CIR/CodeGen/CIRGenerator.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp @@ -152,9 +152,30 @@ void CIRGenerator::HandleTagDeclDefinition(TagDecl *d) { cgm->errorNYI(d->getSourceRange(), "HandleTagDeclDefinition: OpenMP"); } +void CIRGenerator::HandleTagDeclRequiredDefinition(const TagDecl *D) { + if (diags.hasErrorOccurred()) + return; + + assert(!cir::MissingFeatures::generateDebugInfo()); +} + +void CIRGenerator::HandleCXXStaticMemberVarInstantiation(VarDecl *D) { + if (diags.hasErrorOccurred()) + return; + + cgm->errorNYI(D->getSourceRange(), "HandleCXXStaticMemberVarInstantiation"); +} + void CIRGenerator::CompleteTentativeDefinition(VarDecl *d) { if (diags.hasErrorOccurred()) return; cgm->emitTentativeDefinition(d); } + +void CIRGenerator::HandleVTable(CXXRecordDecl *rd) { + if (diags.hasErrorOccurred()) + return; + + cgm->errorNYI(rd->getSourceRange(), "HandleVTable"); +} diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 1c3a310..d3fcac1 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -606,7 +606,7 @@ static Value tryFoldCastChain(cir::CastOp op) { if (!isIntOrBoolCast(op)) break; head = op; - op = dyn_cast_or_null<cir::CastOp>(head.getSrc().getDefiningOp()); + op = head.getSrc().getDefiningOp<cir::CastOp>(); } if (head == tail) @@ -1802,7 +1802,7 @@ OpFoldResult cir::UnaryOp::fold(FoldAdaptor adaptor) { } if (isBoolNot(*this)) - if (auto previous = dyn_cast_or_null<UnaryOp>(getInput().getDefiningOp())) + if (auto previous = getInput().getDefiningOp<cir::UnaryOp>()) if (isBoolNot(previous)) return previous.getInput(); @@ -1833,7 +1833,7 @@ LogicalResult cir::GetMemberOp::verify() { OpFoldResult cir::VecCreateOp::fold(FoldAdaptor adaptor) { if (llvm::any_of(getElements(), [](mlir::Value value) { - return !mlir::isa<cir::ConstantOp>(value.getDefiningOp()); + return !value.getDefiningOp<cir::ConstantOp>(); })) return {}; @@ -2184,8 +2184,7 @@ LogicalResult cir::ComplexRealOp::verify() { } OpFoldResult cir::ComplexRealOp::fold(FoldAdaptor adaptor) { - if (auto complexCreateOp = - dyn_cast_or_null<cir::ComplexCreateOp>(getOperand().getDefiningOp())) + if (auto complexCreateOp = getOperand().getDefiningOp<cir::ComplexCreateOp>()) return complexCreateOp.getOperand(0); auto complex = @@ -2206,8 +2205,7 @@ LogicalResult cir::ComplexImagOp::verify() { } OpFoldResult cir::ComplexImagOp::fold(FoldAdaptor adaptor) { - if (auto complexCreateOp = - dyn_cast_or_null<cir::ComplexCreateOp>(getOperand().getDefiningOp())) + if (auto complexCreateOp = getOperand().getDefiningOp<cir::ComplexCreateOp>()) return complexCreateOp.getOperand(1); auto complex = diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp index 40da5e6..4fecb01 100644 --- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp @@ -698,6 +698,23 @@ BoolType::getABIAlignment(const ::mlir::DataLayout &dataLayout, } //===----------------------------------------------------------------------===// +// VPtrType Definitions +//===----------------------------------------------------------------------===// + +llvm::TypeSize +VPtrType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + // FIXME: consider size differences under different ABIs + return llvm::TypeSize::getFixed(64); +} + +uint64_t VPtrType::getABIAlignment(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + // FIXME: consider alignment differences under different ABIs + return 8; +} + +//===----------------------------------------------------------------------===// // ArrayType Definitions //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp b/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp index 3b7f08c4..3c6f768 100644 --- a/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp @@ -97,8 +97,8 @@ private: // Check whether the region/block contains a cir.const followed by a // cir.yield that yields the value. auto yieldOp = mlir::cast<cir::YieldOp>(onlyBlock.getTerminator()); - auto yieldValueDefOp = mlir::dyn_cast_if_present<cir::ConstantOp>( - yieldOp.getArgs()[0].getDefiningOp()); + auto yieldValueDefOp = + yieldOp.getArgs()[0].getDefiningOp<cir::ConstantOp>(); return yieldValueDefOp && yieldValueDefOp->getBlock() == &onlyBlock; } }; @@ -126,18 +126,13 @@ struct SimplifySelect : public OpRewritePattern<SelectOp> { LogicalResult matchAndRewrite(SelectOp op, PatternRewriter &rewriter) const final { - mlir::Operation *trueValueOp = op.getTrueValue().getDefiningOp(); - mlir::Operation *falseValueOp = op.getFalseValue().getDefiningOp(); - auto trueValueConstOp = - mlir::dyn_cast_if_present<cir::ConstantOp>(trueValueOp); - auto falseValueConstOp = - mlir::dyn_cast_if_present<cir::ConstantOp>(falseValueOp); - if (!trueValueConstOp || !falseValueConstOp) + auto trueValueOp = op.getTrueValue().getDefiningOp<cir::ConstantOp>(); + auto falseValueOp = op.getFalseValue().getDefiningOp<cir::ConstantOp>(); + if (!trueValueOp || !falseValueOp) return mlir::failure(); - auto trueValue = mlir::dyn_cast<cir::BoolAttr>(trueValueConstOp.getValue()); - auto falseValue = - mlir::dyn_cast<cir::BoolAttr>(falseValueConstOp.getValue()); + auto trueValue = trueValueOp.getValueAttr<cir::BoolAttr>(); + auto falseValue = falseValueOp.getValueAttr<cir::BoolAttr>(); if (!trueValue || !falseValue) return mlir::failure(); @@ -265,8 +260,7 @@ struct SimplifyVecSplat : public OpRewritePattern<VecSplatOp> { LogicalResult matchAndRewrite(VecSplatOp op, PatternRewriter &rewriter) const override { mlir::Value splatValue = op.getValue(); - auto constant = - mlir::dyn_cast_if_present<cir::ConstantOp>(splatValue.getDefiningOp()); + auto constant = splatValue.getDefiningOp<cir::ConstantOp>(); if (!constant) return mlir::failure(); diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index ce3b30d..66260eb 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -15,7 +15,6 @@ #include "clang/CIR/Dialect/Passes.h" #include "clang/CIR/MissingFeatures.h" -#include <iostream> #include <memory> using namespace mlir; @@ -28,21 +27,47 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> { void runOnOp(mlir::Operation *op); void lowerCastOp(cir::CastOp op); + void lowerComplexMulOp(cir::ComplexMulOp op); void lowerUnaryOp(cir::UnaryOp op); void lowerArrayDtor(cir::ArrayDtor op); void lowerArrayCtor(cir::ArrayCtor op); + cir::FuncOp buildRuntimeFunction( + mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc, + cir::FuncType type, + cir::GlobalLinkageKind linkage = cir::GlobalLinkageKind::ExternalLinkage); + /// /// AST related /// ----------- clang::ASTContext *astCtx; + /// Tracks current module. + mlir::ModuleOp mlirModule; + void setASTContext(clang::ASTContext *c) { astCtx = c; } }; } // namespace +cir::FuncOp LoweringPreparePass::buildRuntimeFunction( + mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc, + cir::FuncType type, cir::GlobalLinkageKind linkage) { + cir::FuncOp f = dyn_cast_or_null<FuncOp>(SymbolTable::lookupNearestSymbolFrom( + mlirModule, StringAttr::get(mlirModule->getContext(), name))); + if (!f) { + f = builder.create<cir::FuncOp>(loc, name, type); + f.setLinkageAttr( + cir::GlobalLinkageKindAttr::get(builder.getContext(), linkage)); + mlir::SymbolTable::setSymbolVisibility( + f, mlir::SymbolTable::Visibility::Private); + + assert(!cir::MissingFeatures::opFuncExtraAttrs()); + } + return f; +} + static mlir::Value lowerScalarToComplexCast(mlir::MLIRContext &ctx, cir::CastOp op) { cir::CIRBaseBuilderTy builder(ctx); @@ -128,6 +153,124 @@ void LoweringPreparePass::lowerCastOp(cir::CastOp op) { } } +static mlir::Value buildComplexBinOpLibCall( + LoweringPreparePass &pass, CIRBaseBuilderTy &builder, + llvm::StringRef (*libFuncNameGetter)(llvm::APFloat::Semantics), + mlir::Location loc, cir::ComplexType ty, mlir::Value lhsReal, + mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag) { + cir::FPTypeInterface elementTy = + mlir::cast<cir::FPTypeInterface>(ty.getElementType()); + + llvm::StringRef libFuncName = libFuncNameGetter( + llvm::APFloat::SemanticsToEnum(elementTy.getFloatSemantics())); + llvm::SmallVector<mlir::Type, 4> libFuncInputTypes(4, elementTy); + + cir::FuncType libFuncTy = cir::FuncType::get(libFuncInputTypes, ty); + + // Insert a declaration for the runtime function to be used in Complex + // multiplication and division when needed + cir::FuncOp libFunc; + { + mlir::OpBuilder::InsertionGuard ipGuard{builder}; + builder.setInsertionPointToStart(pass.mlirModule.getBody()); + libFunc = pass.buildRuntimeFunction(builder, libFuncName, loc, libFuncTy); + } + + cir::CallOp call = + builder.createCallOp(loc, libFunc, {lhsReal, lhsImag, rhsReal, rhsImag}); + return call.getResult(); +} + +static llvm::StringRef +getComplexMulLibCallName(llvm::APFloat::Semantics semantics) { + switch (semantics) { + case llvm::APFloat::S_IEEEhalf: + return "__mulhc3"; + case llvm::APFloat::S_IEEEsingle: + return "__mulsc3"; + case llvm::APFloat::S_IEEEdouble: + return "__muldc3"; + case llvm::APFloat::S_PPCDoubleDouble: + return "__multc3"; + case llvm::APFloat::S_x87DoubleExtended: + return "__mulxc3"; + case llvm::APFloat::S_IEEEquad: + return "__multc3"; + default: + llvm_unreachable("unsupported floating point type"); + } +} + +static mlir::Value lowerComplexMul(LoweringPreparePass &pass, + CIRBaseBuilderTy &builder, + mlir::Location loc, cir::ComplexMulOp op, + mlir::Value lhsReal, mlir::Value lhsImag, + mlir::Value rhsReal, mlir::Value rhsImag) { + // (a+bi) * (c+di) = (ac-bd) + (ad+bc)i + mlir::Value resultRealLhs = + builder.createBinop(loc, lhsReal, cir::BinOpKind::Mul, rhsReal); + mlir::Value resultRealRhs = + builder.createBinop(loc, lhsImag, cir::BinOpKind::Mul, rhsImag); + mlir::Value resultImagLhs = + builder.createBinop(loc, lhsReal, cir::BinOpKind::Mul, rhsImag); + mlir::Value resultImagRhs = + builder.createBinop(loc, lhsImag, cir::BinOpKind::Mul, rhsReal); + mlir::Value resultReal = builder.createBinop( + loc, resultRealLhs, cir::BinOpKind::Sub, resultRealRhs); + mlir::Value resultImag = builder.createBinop( + loc, resultImagLhs, cir::BinOpKind::Add, resultImagRhs); + mlir::Value algebraicResult = + builder.createComplexCreate(loc, resultReal, resultImag); + + cir::ComplexType complexTy = op.getType(); + cir::ComplexRangeKind rangeKind = op.getRange(); + if (mlir::isa<cir::IntType>(complexTy.getElementType()) || + rangeKind == cir::ComplexRangeKind::Basic || + rangeKind == cir::ComplexRangeKind::Improved || + rangeKind == cir::ComplexRangeKind::Promoted) + return algebraicResult; + + assert(!cir::MissingFeatures::fastMathFlags()); + + // Check whether the real part and the imaginary part of the result are both + // NaN. If so, emit a library call to compute the multiplication instead. + // We check a value against NaN by comparing the value against itself. + mlir::Value resultRealIsNaN = builder.createIsNaN(loc, resultReal); + mlir::Value resultImagIsNaN = builder.createIsNaN(loc, resultImag); + mlir::Value resultRealAndImagAreNaN = + builder.createLogicalAnd(loc, resultRealIsNaN, resultImagIsNaN); + + return builder + .create<cir::TernaryOp>( + loc, resultRealAndImagAreNaN, + [&](mlir::OpBuilder &, mlir::Location) { + mlir::Value libCallResult = buildComplexBinOpLibCall( + pass, builder, &getComplexMulLibCallName, loc, complexTy, + lhsReal, lhsImag, rhsReal, rhsImag); + builder.createYield(loc, libCallResult); + }, + [&](mlir::OpBuilder &, mlir::Location) { + builder.createYield(loc, algebraicResult); + }) + .getResult(); +} + +void LoweringPreparePass::lowerComplexMulOp(cir::ComplexMulOp op) { + cir::CIRBaseBuilderTy builder(getContext()); + builder.setInsertionPointAfter(op); + mlir::Location loc = op.getLoc(); + mlir::TypedValue<cir::ComplexType> lhs = op.getLhs(); + mlir::TypedValue<cir::ComplexType> rhs = op.getRhs(); + mlir::Value lhsReal = builder.createComplexReal(loc, lhs); + mlir::Value lhsImag = builder.createComplexImag(loc, lhs); + mlir::Value rhsReal = builder.createComplexReal(loc, rhs); + mlir::Value rhsImag = builder.createComplexImag(loc, rhs); + mlir::Value loweredResult = lowerComplexMul(*this, builder, loc, op, lhsReal, + lhsImag, rhsReal, rhsImag); + op.replaceAllUsesWith(loweredResult); + op.erase(); +} + void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) { mlir::Type ty = op.getType(); if (!mlir::isa<cir::ComplexType>(ty)) @@ -155,7 +298,8 @@ void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) { case cir::UnaryOpKind::Plus: case cir::UnaryOpKind::Minus: - llvm_unreachable("Complex unary Plus/Minus NYI"); + resultReal = builder.createUnaryOp(loc, opKind, operandReal); + resultImag = builder.createUnaryOp(loc, opKind, operandImag); break; case cir::UnaryOpKind::Not: @@ -268,18 +412,22 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) { lowerArrayDtor(arrayDtor); else if (auto cast = mlir::dyn_cast<cir::CastOp>(op)) lowerCastOp(cast); + else if (auto complexMul = mlir::dyn_cast<cir::ComplexMulOp>(op)) + lowerComplexMulOp(complexMul); else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op)) lowerUnaryOp(unary); } void LoweringPreparePass::runOnOperation() { mlir::Operation *op = getOperation(); + if (isa<::mlir::ModuleOp>(op)) + mlirModule = cast<::mlir::ModuleOp>(op); llvm::SmallVector<mlir::Operation *> opsToTransform; op->walk([&](mlir::Operation *op) { - if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp, cir::UnaryOp>( - op)) + if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp, + cir::ComplexMulOp, cir::UnaryOp>(op)) opsToTransform.push_back(op); }); diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp index 9264aa6..67bb565 100644 --- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp +++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp @@ -84,6 +84,10 @@ public: return true; } + void HandleCXXStaticMemberVarInstantiation(clang::VarDecl *VD) override { + Gen->HandleCXXStaticMemberVarInstantiation(VD); + } + void HandleInlineFunctionDefinition(FunctionDecl *D) override { Gen->HandleInlineFunctionDefinition(D); } @@ -147,9 +151,15 @@ public: Gen->HandleTagDeclDefinition(D); } + void HandleTagDeclRequiredDefinition(const TagDecl *D) override { + Gen->HandleTagDeclRequiredDefinition(D); + } + void CompleteTentativeDefinition(VarDecl *D) override { Gen->CompleteTentativeDefinition(D); } + + void HandleVTable(CXXRecordDecl *RD) override { Gen->HandleVTable(RD); } }; } // namespace cir diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 957a51a..dc6e1b7 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -821,8 +821,7 @@ mlir::LogicalResult CIRToLLVMPtrStrideOpLowering::matchAndRewrite( // before it. To achieve that, look at unary minus, which already got // lowered to "sub 0, x". const auto sub = dyn_cast<mlir::LLVM::SubOp>(indexOp); - auto unary = dyn_cast_if_present<cir::UnaryOp>( - ptrStrideOp.getStride().getDefiningOp()); + auto unary = ptrStrideOp.getStride().getDefiningOp<cir::UnaryOp>(); bool rewriteSub = unary && unary.getKind() == cir::UnaryOpKind::Minus && sub; if (rewriteSub) @@ -1935,12 +1934,11 @@ mlir::LogicalResult CIRToLLVMSelectOpLowering::matchAndRewrite( cir::SelectOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { auto getConstantBool = [](mlir::Value value) -> cir::BoolAttr { - auto definingOp = - mlir::dyn_cast_if_present<cir::ConstantOp>(value.getDefiningOp()); + auto definingOp = value.getDefiningOp<cir::ConstantOp>(); if (!definingOp) return {}; - auto constValue = mlir::dyn_cast<cir::BoolAttr>(definingOp.getValue()); + auto constValue = definingOp.getValueAttr<cir::BoolAttr>(); if (!constValue) return {}; @@ -2379,15 +2377,14 @@ mlir::LogicalResult CIRToLLVMVecSplatOpLowering::matchAndRewrite( mlir::Value poison = rewriter.create<mlir::LLVM::PoisonOp>(loc, llvmTy); mlir::Value elementValue = adaptor.getValue(); - if (mlir::isa<mlir::LLVM::PoisonOp>(elementValue.getDefiningOp())) { + if (elementValue.getDefiningOp<mlir::LLVM::PoisonOp>()) { // If the splat value is poison, then we can just use poison value // for the entire vector. rewriter.replaceOp(op, poison); return mlir::success(); } - if (auto constValue = - dyn_cast<mlir::LLVM::ConstantOp>(elementValue.getDefiningOp())) { + if (auto constValue = elementValue.getDefiningOp<mlir::LLVM::ConstantOp>()) { if (auto intAttr = dyn_cast<mlir::IntegerAttr>(constValue.getValue())) { mlir::DenseIntElementsAttr denseVec = mlir::DenseIntElementsAttr::get( mlir::cast<mlir::ShapedType>(llvmTy), intAttr.getValue()); diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 3f784fc..a648bde 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -973,6 +973,9 @@ public: AddrOfSeen = false; return Visit(E->getSubExpr()); } + const Expr *VisitBinaryOperator(const clang::BinaryOperator *Op) { + return Op->isCommaOp() ? Visit(Op->getRHS()) : nullptr; + } }; } // end anonymous namespace @@ -1148,7 +1151,8 @@ llvm::Value *CodeGenFunction::emitCountedByPointerSize( assert(E->getCastKind() == CK_LValueToRValue && "must be an LValue to RValue cast"); - const MemberExpr *ME = dyn_cast<MemberExpr>(E->getSubExpr()); + const MemberExpr *ME = + dyn_cast<MemberExpr>(E->getSubExpr()->IgnoreParenNoopCasts(getContext())); if (!ME) return nullptr; diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 77fc3a2..1ce834d 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -643,16 +643,7 @@ unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc, bool Force) { } StringRef CGDebugInfo::getCurrentDirname() { - if (!CGM.getCodeGenOpts().DebugCompilationDir.empty()) - return CGM.getCodeGenOpts().DebugCompilationDir; - - if (!CWDName.empty()) - return CWDName; - llvm::ErrorOr<std::string> CWD = - CGM.getFileSystem()->getCurrentWorkingDirectory(); - if (!CWD) - return StringRef(); - return CWDName = internString(*CWD); + return CGM.getCodeGenOpts().DebugCompilationDir; } void CGDebugInfo::CreateCompileUnit() { @@ -2641,6 +2632,8 @@ void CGDebugInfo::emitVTableSymbol(llvm::GlobalVariable *VTable, const CXXRecordDecl *RD) { if (!CGM.getTarget().getCXXABI().isItaniumFamily()) return; + if (DebugKind <= llvm::codegenoptions::DebugLineTablesOnly) + return; ASTContext &Context = CGM.getContext(); StringRef SymbolName = "_vtable$"; @@ -3246,6 +3239,9 @@ llvm::DIModule *CGDebugInfo::getOrCreateModuleRef(ASTSourceDescriptor Mod, std::string Remapped = remapDIPath(Path); StringRef Relative(Remapped); StringRef CompDir = TheCU->getDirectory(); + if (CompDir.empty()) + return Remapped; + if (Relative.consume_front(CompDir)) Relative.consume_front(llvm::sys::path::get_separator()); @@ -4805,7 +4801,7 @@ void CGDebugInfo::EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke, const FunctionDecl *CalleeDecl) { if (!CallOrInvoke) return; - auto *Func = CallOrInvoke->getCalledFunction(); + auto *Func = dyn_cast<llvm::Function>(CallOrInvoke->getCalledOperand()); if (!Func) return; if (Func->getSubprogram()) diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index 411b2e7..497d3a6 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -158,7 +158,6 @@ class CGDebugInfo { /// This is a storage for names that are constructed on demand. For /// example, C++ destructors, C++ operators etc.. llvm::BumpPtrAllocator DebugInfoNames; - StringRef CWDName; llvm::DenseMap<const char *, llvm::TrackingMDRef> DIFileCache; llvm::DenseMap<const FunctionDecl *, llvm::TrackingMDRef> SPCache; diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 90aed79..5a3d4e4 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -93,6 +93,7 @@ static llvm::StringRef GetUBSanTrapForHandler(SanitizerHandler ID) { LIST_SANITIZER_CHECKS #undef SANITIZER_CHECK } + llvm_unreachable("unhandled switch case"); } /// CreateTempAlloca - This creates a alloca and inserts it into the entry diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp index e25b694..04c9192 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -2278,8 +2278,12 @@ void CGOpenMPRuntimeGPU::processRequiresDirective(const OMPRequiresDecl *D) { case OffloadArch::SM_100a: case OffloadArch::SM_101: case OffloadArch::SM_101a: + case OffloadArch::SM_103: + case OffloadArch::SM_103a: case OffloadArch::SM_120: case OffloadArch::SM_120a: + case OffloadArch::SM_121: + case OffloadArch::SM_121a: case OffloadArch::GFX600: case OffloadArch::GFX601: case OffloadArch::GFX602: diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 2c0767f..dc54c97 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -978,7 +978,7 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { CI.getPreprocessor()); std::unique_ptr<BackendConsumer> Result(new BackendConsumer( - CI, BA, &CI.getVirtualFileSystem(), *VMContext, std::move(LinkModules), + CI, BA, CI.getVirtualFileSystemPtr(), *VMContext, std::move(LinkModules), InFile, std::move(OS), CoverageInfo)); BEConsumer = Result.get(); @@ -1156,7 +1156,7 @@ void CodeGenAction::ExecuteAction() { // Set clang diagnostic handler. To do this we need to create a fake // BackendConsumer. - BackendConsumer Result(CI, BA, &CI.getVirtualFileSystem(), *VMContext, + BackendConsumer Result(CI, BA, CI.getVirtualFileSystemPtr(), *VMContext, std::move(LinkModules), "", nullptr, nullptr, TheModule.get()); diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index 4aafac3..38aaceb 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -2449,12 +2449,7 @@ CoverageMappingModuleGen::CoverageMappingModuleGen( : CGM(CGM), SourceInfo(SourceInfo) {} std::string CoverageMappingModuleGen::getCurrentDirname() { - if (!CGM.getCodeGenOpts().CoverageCompilationDir.empty()) - return CGM.getCodeGenOpts().CoverageCompilationDir; - - SmallString<256> CWD; - llvm::sys::fs::current_path(CWD); - return CWD.str().str(); + return CGM.getCodeGenOpts().CoverageCompilationDir; } std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) { diff --git a/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp b/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp index 95971e5..074f2a5 100644 --- a/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp +++ b/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp @@ -146,7 +146,7 @@ public: : CI(CI), Diags(CI.getDiagnostics()), MainFileName(MainFileName), OutputFileName(OutputFileName), Ctx(nullptr), MMap(CI.getPreprocessor().getHeaderSearchInfo().getModuleMap()), - FS(&CI.getVirtualFileSystem()), + FS(CI.getVirtualFileSystemPtr()), HeaderSearchOpts(CI.getHeaderSearchOpts()), PreprocessorOpts(CI.getPreprocessorOpts()), TargetOpts(CI.getTargetOpts()), LangOpts(CI.getLangOpts()), diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp index 6d0f042..fb2a79a 100644 --- a/clang/lib/CrossTU/CrossTranslationUnit.cpp +++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp @@ -563,9 +563,8 @@ CrossTranslationUnitContext::ASTLoader::loadFromDump(StringRef ASTDumpPath) { auto DiagOpts = std::make_shared<DiagnosticOptions>(); TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(llvm::errs(), *DiagOpts); - IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - IntrusiveRefCntPtr<DiagnosticsEngine> Diags( - new DiagnosticsEngine(DiagID, *DiagOpts, DiagClient)); + auto Diags = llvm::makeIntrusiveRefCnt<DiagnosticsEngine>( + DiagnosticIDs::create(), *DiagOpts, DiagClient); return ASTUnit::LoadFromASTFile( ASTDumpPath, CI.getPCHContainerOperations()->getRawReader(), ASTUnit::LoadEverything, DiagOpts, Diags, CI.getFileSystemOpts(), @@ -607,8 +606,8 @@ CrossTranslationUnitContext::ASTLoader::loadFromSource( auto *DiagClient = new ForwardingDiagnosticConsumer{CI.getDiagnosticClient()}; IntrusiveRefCntPtr<DiagnosticIDs> DiagID{ CI.getDiagnostics().getDiagnosticIDs()}; - IntrusiveRefCntPtr<DiagnosticsEngine> Diags( - new DiagnosticsEngine{DiagID, *DiagOpts, DiagClient}); + auto Diags = llvm::makeIntrusiveRefCnt<DiagnosticsEngine>(DiagID, *DiagOpts, + DiagClient); return ASTUnit::LoadFromCommandLine( CommandLineArgs.begin(), (CommandLineArgs.end()), diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 99de951..586f287 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -3606,7 +3606,7 @@ class OffloadingActionBuilder final { if (!CompileDeviceOnly) { C.getDriver().Diag(diag::err_opt_not_valid_without_opt) << "-fhip-emit-relocatable" - << "--cuda-device-only"; + << "--offload-device-only"; } } } @@ -4774,6 +4774,21 @@ Action *Driver::BuildOffloadingActions(Compilation &C, C.isOffloadingHostKind(Action::OFK_HIP) && !Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false); + bool HIPRelocatableObj = + C.isOffloadingHostKind(Action::OFK_HIP) && + Args.hasFlag(options::OPT_fhip_emit_relocatable, + options::OPT_fno_hip_emit_relocatable, false); + + if (!HIPNoRDC && HIPRelocatableObj) + C.getDriver().Diag(diag::err_opt_not_valid_with_opt) + << "-fhip-emit-relocatable" + << "-fgpu-rdc"; + + if (!offloadDeviceOnly() && HIPRelocatableObj) + C.getDriver().Diag(diag::err_opt_not_valid_without_opt) + << "-fhip-emit-relocatable" + << "--offload-device-only"; + // For HIP non-rdc non-device-only compilation, create a linker wrapper // action for each host object to link, bundle and wrap device files in // it. @@ -4894,7 +4909,7 @@ Action *Driver::BuildOffloadingActions(Compilation &C, A->getOffloadingToolChain()->getTriple().isSPIRV(); if ((A->getType() != types::TY_Object && !IsAMDGCNSPIRV && A->getType() != types::TY_LTO_BC) || - !HIPNoRDC || !offloadDeviceOnly()) + HIPRelocatableObj || !HIPNoRDC || !offloadDeviceOnly()) continue; ActionList LinkerInput = {A}; A = C.MakeAction<LinkJobAction>(LinkerInput, types::TY_Image); diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp index 207150e..25a16fe 100644 --- a/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -671,7 +671,8 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { CmdArgs.push_back("--start-group"); AddRunTimeLibs(TC, D, CmdArgs, Args); - CmdArgs.push_back("-lc"); + if (!Args.hasArg(options::OPT_nolibc)) + CmdArgs.push_back("-lc"); if (TC.hasValidGCCInstallation() || detectGCCToolchainAdjacent(D)) CmdArgs.push_back("-lgloss"); CmdArgs.push_back("--end-group"); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index f4674a5..4e1b1d9 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -226,17 +226,19 @@ static bool ShouldEnableAutolink(const ArgList &Args, const ToolChain &TC, static const char *addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs, const llvm::vfs::FileSystem &VFS) { + std::string DebugCompDir; if (Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ, - options::OPT_fdebug_compilation_dir_EQ)) { - if (A->getOption().matches(options::OPT_ffile_compilation_dir_EQ)) - CmdArgs.push_back(Args.MakeArgString(Twine("-fdebug-compilation-dir=") + - A->getValue())); + options::OPT_fdebug_compilation_dir_EQ)) + DebugCompDir = A->getValue(); + + if (DebugCompDir.empty()) { + if (llvm::ErrorOr<std::string> CWD = VFS.getCurrentWorkingDirectory()) + DebugCompDir = std::move(*CWD); else - A->render(Args, CmdArgs); - } else if (llvm::ErrorOr<std::string> CWD = - VFS.getCurrentWorkingDirectory()) { - CmdArgs.push_back(Args.MakeArgString("-fdebug-compilation-dir=" + *CWD)); + return nullptr; } + CmdArgs.push_back( + Args.MakeArgString("-fdebug-compilation-dir=" + DebugCompDir)); StringRef Path(CmdArgs.back()); return Path.substr(Path.find('=') + 1).data(); } @@ -525,17 +527,17 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, CmdArgs.push_back("-fcoverage-mcdc"); } + StringRef CoverageCompDir; if (Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ, - options::OPT_fcoverage_compilation_dir_EQ)) { - if (A->getOption().matches(options::OPT_ffile_compilation_dir_EQ)) - CmdArgs.push_back(Args.MakeArgString( - Twine("-fcoverage-compilation-dir=") + A->getValue())); - else - A->render(Args, CmdArgs); - } else if (llvm::ErrorOr<std::string> CWD = - D.getVFS().getCurrentWorkingDirectory()) { - CmdArgs.push_back(Args.MakeArgString("-fcoverage-compilation-dir=" + *CWD)); - } + options::OPT_fcoverage_compilation_dir_EQ)) + CoverageCompDir = A->getValue(); + if (CoverageCompDir.empty()) { + if (auto CWD = D.getVFS().getCurrentWorkingDirectory()) + CmdArgs.push_back( + Args.MakeArgString(Twine("-fcoverage-compilation-dir=") + *CWD)); + } else + CmdArgs.push_back(Args.MakeArgString(Twine("-fcoverage-compilation-dir=") + + CoverageCompDir)); if (Args.hasArg(options::OPT_fprofile_exclude_files_EQ)) { auto *Arg = Args.getLastArg(options::OPT_fprofile_exclude_files_EQ); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 256c266..334fcbb 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -295,17 +295,22 @@ static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, Format = A->getValue(); SmallString<128> F; - const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); - if (A) + if (const Arg *A = + Args.getLastArg(options::OPT_foptimization_record_file_EQ)) { + F = A->getValue(); + F += "."; + } else if (const Arg *A = Args.getLastArg(options::OPT_dumpdir)) { F = A->getValue(); - else if (Output.isFilename()) + } else if (Output.isFilename()) { F = Output.getFilename(); + F += "."; + } assert(!F.empty() && "Cannot determine remarks output name."); // Append "opt.ld.<format>" to the end of the file name. CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + - "opt-remarks-filename=" + F + - ".opt.ld." + Format)); + "opt-remarks-filename=" + F + "opt.ld." + + Format)); if (const Arg *A = Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) @@ -1075,9 +1080,17 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, } } - if (Args.hasArg(options::OPT_gsplit_dwarf)) - CmdArgs.push_back(Args.MakeArgString( - Twine(PluginOptPrefix) + "dwo_dir=" + Output.getFilename() + "_dwo")); + if (Args.hasArg(options::OPT_gsplit_dwarf)) { + SmallString<128> F; + if (const Arg *A = Args.getLastArg(options::OPT_dumpdir)) { + F = A->getValue(); + } else { + F = Output.getFilename(); + F += "_"; + } + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "dwo_dir=" + F + "dwo")); + } if (IsThinLTO && !IsOSAIX) CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + "thinlto")); @@ -3001,12 +3014,12 @@ void tools::addOffloadCompressArgs(const llvm::opt::ArgList &TCArgs, llvm::opt::ArgStringList &CmdArgs) { if (TCArgs.hasFlag(options::OPT_offload_compress, options::OPT_no_offload_compress, false)) - CmdArgs.push_back("-compress"); + CmdArgs.push_back("--compress"); if (TCArgs.hasArg(options::OPT_v)) - CmdArgs.push_back("-verbose"); + CmdArgs.push_back("--verbose"); if (auto *Arg = TCArgs.getLastArg(options::OPT_offload_compression_level_EQ)) CmdArgs.push_back( - TCArgs.MakeArgString(Twine("-compression-level=") + Arg->getValue())); + TCArgs.MakeArgString(Twine("--compression-level=") + Arg->getValue())); } void tools::addMCModel(const Driver &D, const llvm::opt::ArgList &Args, diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 7d803be..fdfcea8 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -88,6 +88,8 @@ CudaVersion getCudaVersion(uint32_t raw_version) { return CudaVersion::CUDA_126; if (raw_version < 12090) return CudaVersion::CUDA_128; + if (raw_version < 13000) + return CudaVersion::CUDA_129; return CudaVersion::NEW; } @@ -547,22 +549,16 @@ void NVPTX::FatBinary::ConstructJob(Compilation &C, const JobAction &JA, auto *A = II.getAction(); assert(A->getInputs().size() == 1 && "Device offload action is expected to have a single input"); - const char *gpu_arch_str = A->getOffloadingArch(); - assert(gpu_arch_str && + StringRef GpuArch = A->getOffloadingArch(); + assert(!GpuArch.empty() && "Device action expected to have associated a GPU architecture!"); - OffloadArch gpu_arch = StringToOffloadArch(gpu_arch_str); - if (II.getType() == types::TY_PP_Asm && - !shouldIncludePTX(Args, gpu_arch_str)) + if (II.getType() == types::TY_PP_Asm && !shouldIncludePTX(Args, GpuArch)) continue; - // We need to pass an Arch of the form "sm_XX" for cubin files and - // "compute_XX" for ptx. - const char *Arch = (II.getType() == types::TY_PP_Asm) - ? OffloadArchToVirtualArchString(gpu_arch) - : gpu_arch_str; - CmdArgs.push_back( - Args.MakeArgString(llvm::Twine("--image=profile=") + Arch + - ",file=" + getToolChain().getInputFilename(II))); + StringRef Kind = (II.getType() == types::TY_PP_Asm) ? "ptx" : "elf"; + CmdArgs.push_back(Args.MakeArgString( + "--image3=kind=" + Kind + ",sm=" + GpuArch.drop_front(3) + + ",file=" + getToolChain().getInputFilename(II))); } for (const auto &A : Args.getAllArgValues(options::OPT_Xcuda_fatbinary)) @@ -683,6 +679,7 @@ void NVPTX::getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple, case CudaVersion::CUDA_##CUDA_VER: \ PtxFeature = "+ptx" #PTX_VER; \ break; + CASE_CUDA_VERSION(129, 88); CASE_CUDA_VERSION(128, 87); CASE_CUDA_VERSION(126, 85); CASE_CUDA_VERSION(125, 85); diff --git a/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp b/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp index 80487fa..b51991bf 100644 --- a/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp +++ b/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp @@ -45,15 +45,18 @@ std::pair<tooling::Replacements, unsigned> IntegerLiteralSeparatorFixer::process(const Environment &Env, const FormatStyle &Style) { switch (Style.Language) { - case FormatStyle::LK_Cpp: - case FormatStyle::LK_ObjC: - Separator = '\''; - break; case FormatStyle::LK_CSharp: case FormatStyle::LK_Java: case FormatStyle::LK_JavaScript: Separator = '_'; break; + case FormatStyle::LK_Cpp: + case FormatStyle::LK_ObjC: + if (Style.Standard >= FormatStyle::LS_Cpp14) { + Separator = '\''; + break; + } + [[fallthrough]]; default: return {}; } @@ -114,7 +117,7 @@ IntegerLiteralSeparatorFixer::process(const Environment &Env, } if (Style.isCpp()) { // Hex alpha digits a-f/A-F must be at the end of the string literal. - StringRef Suffixes = "_himnsuyd"; + static constexpr StringRef Suffixes("_himnsuyd"); if (const auto Pos = Text.find_first_of(IsBase16 ? Suffixes.drop_back() : Suffixes); Pos != StringRef::npos) { diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index d28d2fd..4801d27 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -1939,7 +1939,7 @@ private: Contexts.back().IsExpression = true; next(); if (CurrentToken) - CurrentToken->SpacesRequiredBefore = true; + CurrentToken->SpacesRequiredBefore = 1; parseLine(); break; default: @@ -2639,8 +2639,8 @@ private: if (PreviousNotConst->is(TT_TemplateCloser)) { return PreviousNotConst && PreviousNotConst->MatchingParen && PreviousNotConst->MatchingParen->Previous && - PreviousNotConst->MatchingParen->Previous->isNot(tok::period) && - PreviousNotConst->MatchingParen->Previous->isNot(tok::kw_template); + !PreviousNotConst->MatchingParen->Previous->isOneOf( + tok::period, tok::kw_template); } if ((PreviousNotConst->is(tok::r_paren) && @@ -3369,7 +3369,7 @@ private: Current->isOneOf(Keywords.kw_in, Keywords.kw_as)) { return prec::Relational; } - if (Current->is(TT_BinaryOperator) || Current->is(tok::comma)) + if (Current->isOneOf(TT_BinaryOperator, tok::comma)) return Current->getPrecedence(); if (Current->isOneOf(tok::period, tok::arrow) && Current->isNot(TT_TrailingReturnArrow)) { @@ -4314,8 +4314,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, if (Left.is(tok::coloncolon)) return Style.PenaltyBreakScopeResolution; - if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) || - Right.is(tok::kw_operator)) { + if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName, + tok::kw_operator)) { if (Line.startsWith(tok::kw_for) && Right.PartOfMultiVariableDeclStmt) return 3; if (Left.is(TT_StartOfName)) @@ -4757,7 +4757,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Previous) { if (Previous->endsSequence(tok::kw_operator)) return Style.PointerAlignment != FormatStyle::PAS_Left; - if (Previous->is(tok::kw_const) || Previous->is(tok::kw_volatile)) { + if (Previous->isOneOf(tok::kw_const, tok::kw_volatile)) { return (Style.PointerAlignment != FormatStyle::PAS_Left) || (Style.SpaceAroundPointerQualifiers == FormatStyle::SAPQ_After) || @@ -4931,8 +4931,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, } if (Left.is(TT_TemplateCloser) && Left.MatchingParen && Left.MatchingParen->Previous && - (Left.MatchingParen->Previous->is(tok::period) || - Left.MatchingParen->Previous->is(tok::coloncolon))) { + Left.MatchingParen->Previous->isOneOf(tok::period, tok::coloncolon)) { // Java call to generic function with explicit type: // A.<B<C<...>>>DoSomething(); // A::<B<C<...>>>DoSomething(); // With a Java 8 method reference. @@ -5207,8 +5206,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, // (e.g. as "const x of y" in a for loop), or after a destructuring // operation (const [x, y] of z, const {a, b} of c). (Left.is(Keywords.kw_of) && BeforeLeft && - (BeforeLeft->is(tok::identifier) || - BeforeLeft->isOneOf(tok::r_square, tok::r_brace)))) && + BeforeLeft->isOneOf(tok::identifier, tok::r_square, tok::r_brace))) && (!BeforeLeft || BeforeLeft->isNot(tok::period))) { return true; } @@ -5516,7 +5514,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return false; } if (Style.isJava() && Right.is(tok::coloncolon) && - (Left.is(tok::identifier) || Left.is(tok::kw_this))) { + Left.isOneOf(tok::identifier, tok::kw_this)) { return false; } if (Right.is(tok::coloncolon) && Left.is(tok::identifier)) { @@ -5587,8 +5585,8 @@ static bool IsFunctionArgument(const FormatToken &Tok) { } static bool -isItAnEmptyLambdaAllowed(const FormatToken &Tok, - FormatStyle::ShortLambdaStyle ShortLambdaOption) { +isEmptyLambdaAllowed(const FormatToken &Tok, + FormatStyle::ShortLambdaStyle ShortLambdaOption) { return Tok.Children.empty() && ShortLambdaOption != FormatStyle::SLS_None; } @@ -5808,8 +5806,8 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, } if (Right.is(tok::comment)) { - return Left.isNot(BK_BracedInit) && Left.isNot(TT_CtorInitializerColon) && - (Right.NewlinesBefore > 0 && Right.HasUnescapedNewline); + return !Left.isOneOf(BK_BracedInit, TT_CtorInitializerColon) && + Right.NewlinesBefore > 0 && Right.HasUnescapedNewline; } if (Left.isTrailingComment()) return true; @@ -5977,7 +5975,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, // Put multiple Java annotation on a new line. if ((Style.isJava() || Style.isJavaScript()) && Left.is(TT_LeadingJavaAnnotation) && - Right.isNot(TT_LeadingJavaAnnotation) && Right.isNot(tok::l_paren) && + !Right.isOneOf(TT_LeadingJavaAnnotation, tok::l_paren) && (Line.Last->is(tok::l_brace) || Style.BreakAfterJavaFieldAnnotations)) { return true; } @@ -6043,7 +6041,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, ((LBrace->is(tok::l_brace) && (LBrace->is(TT_DictLiteral) || (LBrace->Next && LBrace->Next->is(tok::r_brace)))) || - LBrace->is(TT_ArrayInitializerLSquare) || LBrace->is(tok::less))) { + LBrace->isOneOf(TT_ArrayInitializerLSquare, tok::less))) { // If Left.ParameterCount is 0, then this submessage entry is not the // first in its parent submessage, and we want to break before this entry. // If Left.ParameterCount is greater than 0, then its parent submessage @@ -6257,9 +6255,9 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, } if (Left.is(tok::question) && Right.is(tok::colon)) return false; - if (Right.is(TT_ConditionalExpr) || Right.is(tok::question)) + if (Right.isOneOf(TT_ConditionalExpr, tok::question)) return Style.BreakBeforeTernaryOperators; - if (Left.is(TT_ConditionalExpr) || Left.is(tok::question)) + if (Left.isOneOf(TT_ConditionalExpr, tok::question)) return !Style.BreakBeforeTernaryOperators; if (Left.is(TT_InheritanceColon)) return Style.BreakInheritanceList == FormatStyle::BILS_AfterColon; @@ -6302,7 +6300,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, // submessage: { ... } // submessage: < ... > // repeated: [ ... ] - if (((Right.is(tok::l_brace) || Right.is(tok::less)) && + if ((Right.isOneOf(tok::l_brace, tok::less) && Right.is(TT_DictLiteral)) || Right.is(TT_ArrayInitializerLSquare)) { return false; @@ -6352,10 +6350,8 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, Right.getPrecedence() != prec::Assignment)) { return true; } - if (Left.isOneOf(TT_TemplateCloser, TT_UnaryOperator) || - Left.is(tok::kw_operator)) { + if (Left.isOneOf(TT_TemplateCloser, TT_UnaryOperator, tok::kw_operator)) return false; - } if (Left.is(tok::equal) && !Right.isOneOf(tok::kw_default, tok::kw_delete) && Line.Type == LT_VirtualFunctionDecl && Left.NestingLevel == 0) { return false; @@ -6440,9 +6436,9 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, auto ShortLambdaOption = Style.AllowShortLambdasOnASingleLine; if (Style.BraceWrapping.BeforeLambdaBody && Right.is(TT_LambdaLBrace)) { if (isAllmanLambdaBrace(Left)) - return !isItAnEmptyLambdaAllowed(Left, ShortLambdaOption); + return !isEmptyLambdaAllowed(Left, ShortLambdaOption); if (isAllmanLambdaBrace(Right)) - return !isItAnEmptyLambdaAllowed(Right, ShortLambdaOption); + return !isEmptyLambdaAllowed(Right, ShortLambdaOption); } if (Right.is(tok::kw_noexcept) && Right.is(TT_TrailingAnnotation)) { diff --git a/clang/lib/Frontend/ASTMerge.cpp b/clang/lib/Frontend/ASTMerge.cpp index a4ce883..10c1045 100644 --- a/clang/lib/Frontend/ASTMerge.cpp +++ b/clang/lib/Frontend/ASTMerge.cpp @@ -41,10 +41,10 @@ void ASTMergeAction::ExecuteAction() { auto SharedState = std::make_shared<ASTImporterSharedState>( *CI.getASTContext().getTranslationUnitDecl()); for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) { - IntrusiveRefCntPtr<DiagnosticsEngine> Diags(new DiagnosticsEngine( + auto Diags = llvm::makeIntrusiveRefCnt<DiagnosticsEngine>( DiagIDs, CI.getDiagnosticOpts(), new ForwardingDiagnosticConsumer(*CI.getDiagnostics().getClient()), - /*ShouldOwnClient=*/true)); + /*ShouldOwnClient=*/true); std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile( ASTFiles[I], CI.getPCHContainerReader(), ASTUnit::LoadEverything, nullptr, Diags, CI.getFileSystemOpts(), CI.getHeaderSearchOpts()); diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index 67ed17b..a407825 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -831,11 +831,10 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( AST->CaptureDiagnostics = CaptureDiagnostics; AST->DiagOpts = DiagOpts; AST->Diagnostics = Diags; - AST->FileMgr = new FileManager(FileSystemOpts, VFS); + AST->FileMgr = llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOpts, VFS); AST->UserFilesAreVolatile = UserFilesAreVolatile; - AST->SourceMgr = new SourceManager(AST->getDiagnostics(), - AST->getFileManager(), - UserFilesAreVolatile); + AST->SourceMgr = llvm::makeIntrusiveRefCnt<SourceManager>( + AST->getDiagnostics(), AST->getFileManager(), UserFilesAreVolatile); AST->ModCache = createCrossProcessModuleCache(); AST->HSOpts = std::make_unique<HeaderSearchOptions>(HSOpts); AST->HSOpts->ModuleFormat = std::string(PCHContainerRdr.getFormats().front()); @@ -858,20 +857,20 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( Preprocessor &PP = *AST->PP; if (ToLoad >= LoadASTOnly) - AST->Ctx = new ASTContext(*AST->LangOpts, AST->getSourceManager(), - PP.getIdentifierTable(), PP.getSelectorTable(), - PP.getBuiltinInfo(), - AST->getTranslationUnitKind()); + AST->Ctx = llvm::makeIntrusiveRefCnt<ASTContext>( + *AST->LangOpts, AST->getSourceManager(), PP.getIdentifierTable(), + PP.getSelectorTable(), PP.getBuiltinInfo(), + AST->getTranslationUnitKind()); DisableValidationForModuleKind disableValid = DisableValidationForModuleKind::None; if (::getenv("LIBCLANG_DISABLE_PCH_VALIDATION")) disableValid = DisableValidationForModuleKind::All; - AST->Reader = new ASTReader(PP, *AST->ModCache, AST->Ctx.get(), - PCHContainerRdr, *AST->CodeGenOpts, {}, - /*isysroot=*/"", - /*DisableValidationKind=*/disableValid, - AllowASTWithCompilerErrors); + AST->Reader = llvm::makeIntrusiveRefCnt<ASTReader>( + PP, *AST->ModCache, AST->Ctx.get(), PCHContainerRdr, *AST->CodeGenOpts, + ArrayRef<std::shared_ptr<ModuleFileExtension>>(), + /*isysroot=*/"", + /*DisableValidationKind=*/disableValid, AllowASTWithCompilerErrors); unsigned Counter = 0; AST->Reader->setListener(std::make_unique<ASTInfoCollector>( @@ -1191,9 +1190,11 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, // changed above in AddImplicitPreamble. If VFS is nullptr, rely on // createFileManager to create one. if (VFS && FileMgr && &FileMgr->getVirtualFileSystem() == VFS) - Clang->setFileManager(&*FileMgr); - else - FileMgr = Clang->createFileManager(std::move(VFS)); + Clang->setFileManager(FileMgr); + else { + Clang->createFileManager(std::move(VFS)); + FileMgr = Clang->getFileManagerPtr(); + } // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> @@ -1204,7 +1205,7 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, // Set up diagnostics, capturing any diagnostics that would // otherwise be dropped. - Clang->setDiagnostics(&getDiagnostics()); + Clang->setDiagnostics(getDiagnosticsPtr()); // Create the target instance. if (!Clang->createTarget()) @@ -1226,15 +1227,15 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, ResetForParse(); - SourceMgr = new SourceManager(getDiagnostics(), *FileMgr, - UserFilesAreVolatile); + SourceMgr = llvm::makeIntrusiveRefCnt<SourceManager>( + getDiagnostics(), *FileMgr, +UserFilesAreVolatile); if (!OverrideMainBuffer) { checkAndRemoveNonDriverDiags(StoredDiagnostics); TopLevelDeclsInPreamble.clear(); } // Create the source manager. - Clang->setSourceManager(&getSourceManager()); + Clang->setSourceManager(getSourceManagerPtr()); // If the main file has been overridden due to the use of a preamble, // make that override happen and introduce the preamble. @@ -1424,7 +1425,7 @@ ASTUnit::getMainBufferWithPrecompiledPreamble( PreambleInvocationIn.getFrontendOpts().SkipFunctionBodies = true; llvm::ErrorOr<PrecompiledPreamble> NewPreamble = PrecompiledPreamble::Build( - PreambleInvocationIn, MainFileBuffer.get(), Bounds, *Diagnostics, VFS, + PreambleInvocationIn, MainFileBuffer.get(), Bounds, Diagnostics, VFS, PCHContainerOps, StorePreamblesInMemory, PreambleStoragePath, Callbacks); @@ -1499,13 +1500,13 @@ void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) { TheSema = CI.takeSema(); Consumer = CI.takeASTConsumer(); if (CI.hasASTContext()) - Ctx = &CI.getASTContext(); + Ctx = CI.getASTContextPtr(); if (CI.hasPreprocessor()) PP = CI.getPreprocessorPtr(); CI.setSourceManager(nullptr); CI.setFileManager(nullptr); if (CI.hasTarget()) - Target = &CI.getTarget(); + Target = CI.getTargetPtr(); Reader = CI.getASTReader(); HadModuleLoaderFatalFailure = CI.hadModuleLoaderFatalFailure(); if (Invocation != CI.getInvocationPtr()) { @@ -1555,10 +1556,11 @@ ASTUnit::create(std::shared_ptr<CompilerInvocation> CI, AST->Diagnostics = Diags; AST->FileSystemOpts = CI->getFileSystemOpts(); AST->Invocation = std::move(CI); - AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS); + AST->FileMgr = + llvm::makeIntrusiveRefCnt<FileManager>(AST->FileSystemOpts, VFS); AST->UserFilesAreVolatile = UserFilesAreVolatile; - AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr, - UserFilesAreVolatile); + AST->SourceMgr = llvm::makeIntrusiveRefCnt<SourceManager>( + AST->getDiagnostics(), *AST->FileMgr, UserFilesAreVolatile); AST->ModCache = createCrossProcessModuleCache(); return AST; @@ -1624,7 +1626,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction( // Set up diagnostics, capturing any diagnostics that would // otherwise be dropped. - Clang->setDiagnostics(&AST->getDiagnostics()); + Clang->setDiagnostics(AST->getDiagnosticsPtr()); // Create the target instance. if (!Clang->createTarget()) @@ -1646,10 +1648,10 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction( AST->Reader = nullptr; // Create a file manager object to provide access to and cache the filesystem. - Clang->setFileManager(&AST->getFileManager()); + Clang->setFileManager(AST->getFileManagerPtr()); // Create the source manager. - Clang->setSourceManager(&AST->getSourceManager()); + Clang->setSourceManager(AST->getSourceManagerPtr()); FrontendAction *Act = Action; @@ -1743,8 +1745,9 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation( std::shared_ptr<CompilerInvocation> CI, std::shared_ptr<PCHContainerOperations> PCHContainerOps, std::shared_ptr<DiagnosticOptions> DiagOpts, - IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FileManager *FileMgr, - bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, + IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + IntrusiveRefCntPtr<FileManager> FileMgr, bool OnlyLocalDecls, + CaptureDiagsKind CaptureDiagnostics, unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, bool UserFilesAreVolatile) { @@ -1773,7 +1776,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation( if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps), PrecompilePreambleAfterNParses, - &AST->FileMgr->getVirtualFileSystem())) + AST->FileMgr->getVirtualFileSystemPtr())) return nullptr; return AST; } @@ -1849,7 +1852,8 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCommandLine( AST->FileSystemOpts = CI->getFileSystemOpts(); AST->CodeGenOpts = std::make_unique<CodeGenOptions>(CI->getCodeGenOpts()); VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS); - AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS); + AST->FileMgr = + llvm::makeIntrusiveRefCnt<FileManager>(AST->FileSystemOpts, VFS); AST->StorePreamblesInMemory = StorePreamblesInMemory; AST->PreambleStoragePath = PreambleStoragePath; AST->ModCache = createCrossProcessModuleCache(); @@ -1895,7 +1899,7 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, if (!VFS) { assert(FileMgr && "FileMgr is null on Reparse call"); - VFS = &FileMgr->getVirtualFileSystem(); + VFS = FileMgr->getVirtualFileSystemPtr(); } clearFileLevelDecls(); @@ -2209,8 +2213,10 @@ void ASTUnit::CodeComplete( bool IncludeCodePatterns, bool IncludeBriefComments, CodeCompleteConsumer &Consumer, std::shared_ptr<PCHContainerOperations> PCHContainerOps, - DiagnosticsEngine &Diag, LangOptions &LangOpts, SourceManager &SourceMgr, - FileManager &FileMgr, SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics, + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diag, LangOptions &LangOpts, + llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr, + llvm::IntrusiveRefCntPtr<FileManager> FileMgr, + SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics, SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers, std::unique_ptr<SyntaxOnlyAction> Act) { if (!Invocation) @@ -2259,12 +2265,12 @@ void ASTUnit::CodeComplete( std::string(Clang->getFrontendOpts().Inputs[0].getFile()); // Set up diagnostics, capturing any diagnostics produced. - Clang->setDiagnostics(&Diag); + Clang->setDiagnostics(Diag); CaptureDroppedDiagnostics Capture(CaptureDiagsKind::All, Clang->getDiagnostics(), &StoredDiagnostics, nullptr); - ProcessWarningOptions(Diag, Inv.getDiagnosticOpts(), - FileMgr.getVirtualFileSystem()); + ProcessWarningOptions(*Diag, Inv.getDiagnosticOpts(), + FileMgr->getVirtualFileSystem()); // Create the target instance. if (!Clang->createTarget()) { @@ -2281,8 +2287,8 @@ void ASTUnit::CodeComplete( "IR inputs not support here!"); // Use the source and file managers that we were given. - Clang->setFileManager(&FileMgr); - Clang->setSourceManager(&SourceMgr); + Clang->setFileManager(FileMgr); + Clang->setSourceManager(SourceMgr); // Remap files. PreprocessorOpts.clearRemappedFiles(); @@ -2300,7 +2306,7 @@ void ASTUnit::CodeComplete( auto getUniqueID = [&FileMgr](StringRef Filename) -> std::optional<llvm::sys::fs::UniqueID> { - if (auto Status = FileMgr.getVirtualFileSystem().status(Filename)) + if (auto Status = FileMgr->getVirtualFileSystem().status(Filename)) return Status->getUniqueID(); return std::nullopt; }; @@ -2321,7 +2327,8 @@ void ASTUnit::CodeComplete( std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer; if (Preamble && Line > 1 && hasSameUniqueID(File, OriginalSourceFile)) { OverrideMainBuffer = getMainBufferWithPrecompiledPreamble( - PCHContainerOps, Inv, &FileMgr.getVirtualFileSystem(), false, Line - 1); + PCHContainerOps, Inv, FileMgr->getVirtualFileSystemPtr(), false, + Line - 1); } // If the main file has been overridden due to the use of a preamble, @@ -2331,7 +2338,7 @@ void ASTUnit::CodeComplete( "No preamble was built, but OverrideMainBuffer is not null"); IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = - &FileMgr.getVirtualFileSystem(); + FileMgr->getVirtualFileSystemPtr(); Preamble->AddImplicitPreamble(Clang->getInvocation(), VFS, OverrideMainBuffer.get()); // FIXME: there is no way to update VFS if it was changed by diff --git a/clang/lib/Frontend/ChainedIncludesSource.cpp b/clang/lib/Frontend/ChainedIncludesSource.cpp index ba7c767..013814a 100644 --- a/clang/lib/Frontend/ChainedIncludesSource.cpp +++ b/clang/lib/Frontend/ChainedIncludesSource.cpp @@ -53,17 +53,17 @@ private: }; } // end anonymous namespace -static ASTReader * +static llvm::IntrusiveRefCntPtr<ASTReader> createASTReader(CompilerInstance &CI, StringRef pchFile, SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>> &MemBufs, SmallVectorImpl<std::string> &bufNames, ASTDeserializationListener *deserialListener = nullptr) { Preprocessor &PP = CI.getPreprocessor(); - std::unique_ptr<ASTReader> Reader; - Reader.reset(new ASTReader( + auto Reader = llvm::makeIntrusiveRefCnt<ASTReader>( PP, CI.getModuleCache(), &CI.getASTContext(), CI.getPCHContainerReader(), - CI.getCodeGenOpts(), /*Extensions=*/{}, - /*isysroot=*/"", DisableValidationForModuleKind::PCH)); + CI.getCodeGenOpts(), + /*Extensions=*/ArrayRef<std::shared_ptr<ModuleFileExtension>>(), + /*isysroot=*/"", DisableValidationForModuleKind::PCH); for (unsigned ti = 0; ti < bufNames.size(); ++ti) { StringRef sr(bufNames[ti]); Reader->addInMemoryBuffer(sr, std::move(MemBufs[ti])); @@ -74,7 +74,7 @@ createASTReader(CompilerInstance &CI, StringRef pchFile, case ASTReader::Success: // Set the predefines buffer as suggested by the PCH reader. PP.setPredefines(Reader->getSuggestedPredefines()); - return Reader.release(); + return Reader; case ASTReader::Failure: case ASTReader::Missing: @@ -87,8 +87,9 @@ createASTReader(CompilerInstance &CI, StringRef pchFile, return nullptr; } -IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource( - CompilerInstance &CI, IntrusiveRefCntPtr<ExternalSemaSource> &Reader) { +IntrusiveRefCntPtr<ExternalSemaSource> +clang::createChainedIncludesSource(CompilerInstance &CI, + IntrusiveRefCntPtr<ASTReader> &OutReader) { std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes; assert(!includes.empty() && "No '-chain-include' in options!"); @@ -118,13 +119,12 @@ IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource( TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(llvm::errs(), CI.getDiagnosticOpts()); - IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - IntrusiveRefCntPtr<DiagnosticsEngine> Diags( - new DiagnosticsEngine(DiagID, CI.getDiagnosticOpts(), DiagClient)); + auto Diags = llvm::makeIntrusiveRefCnt<DiagnosticsEngine>( + DiagnosticIDs::create(), CI.getDiagnosticOpts(), DiagClient); auto Clang = std::make_unique<CompilerInstance>( std::move(CInvok), CI.getPCHContainerOperations()); - Clang->setDiagnostics(Diags.get()); + Clang->setDiagnostics(Diags); Clang->setTarget(TargetInfo::CreateTargetInfo( Clang->getDiagnostics(), Clang->getInvocation().getTargetOpts())); Clang->createFileManager(); @@ -187,12 +187,12 @@ IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource( assert(!SerialBufs.empty()); std::string pchName = includes.back() + ".pch-final"; serialBufNames.push_back(pchName); - Reader = createASTReader(CI, pchName, SerialBufs, serialBufNames); - if (!Reader) + OutReader = createASTReader(CI, pchName, SerialBufs, serialBufNames); + if (!OutReader) return nullptr; auto ChainedSrc = llvm::makeIntrusiveRefCnt<ChainedIncludesSource>(std::move(CIs)); return llvm::makeIntrusiveRefCnt<MultiplexExternalSemaSource>( - ChainedSrc.get(), Reader.get()); + std::move(ChainedSrc), OutReader); } diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index c7b82db..d64290f 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -87,8 +87,9 @@ bool CompilerInstance::shouldBuildGlobalModuleIndex() const { !DisableGeneratingGlobalModuleIndex; } -void CompilerInstance::setDiagnostics(DiagnosticsEngine *Value) { - Diagnostics = Value; +void CompilerInstance::setDiagnostics( + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Value) { + Diagnostics = std::move(Value); } void CompilerInstance::setVerboseOutputStream(raw_ostream &Value) { @@ -160,20 +161,28 @@ llvm::vfs::FileSystem &CompilerInstance::getVirtualFileSystem() const { return getFileManager().getVirtualFileSystem(); } -void CompilerInstance::setFileManager(FileManager *Value) { - FileMgr = Value; +llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> +CompilerInstance::getVirtualFileSystemPtr() const { + return getFileManager().getVirtualFileSystemPtr(); } -void CompilerInstance::setSourceManager(SourceManager *Value) { - SourceMgr = Value; +void CompilerInstance::setFileManager( + llvm::IntrusiveRefCntPtr<FileManager> Value) { + FileMgr = std::move(Value); +} + +void CompilerInstance::setSourceManager( + llvm::IntrusiveRefCntPtr<SourceManager> Value) { + SourceMgr = std::move(Value); } void CompilerInstance::setPreprocessor(std::shared_ptr<Preprocessor> Value) { PP = std::move(Value); } -void CompilerInstance::setASTContext(ASTContext *Value) { - Context = Value; +void CompilerInstance::setASTContext( + llvm::IntrusiveRefCntPtr<ASTContext> Value) { + Context = std::move(Value); if (Context && Consumer) getASTConsumer().Initialize(getASTContext()); @@ -340,9 +349,8 @@ IntrusiveRefCntPtr<DiagnosticsEngine> CompilerInstance::createDiagnostics( llvm::vfs::FileSystem &VFS, DiagnosticOptions &Opts, DiagnosticConsumer *Client, bool ShouldOwnClient, const CodeGenOptions *CodeGenOpts) { - IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - IntrusiveRefCntPtr<DiagnosticsEngine> Diags( - new DiagnosticsEngine(DiagID, Opts)); + auto Diags = llvm::makeIntrusiveRefCnt<DiagnosticsEngine>( + DiagnosticIDs::create(), Opts); // Create the diagnostic client for reporting errors or for // implementing -verify. @@ -375,21 +383,23 @@ IntrusiveRefCntPtr<DiagnosticsEngine> CompilerInstance::createDiagnostics( FileManager *CompilerInstance::createFileManager( IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) { if (!VFS) - VFS = FileMgr ? &FileMgr->getVirtualFileSystem() + VFS = FileMgr ? FileMgr->getVirtualFileSystemPtr() : createVFSFromCompilerInvocation(getInvocation(), getDiagnostics()); assert(VFS && "FileManager has no VFS?"); if (getFrontendOpts().ShowStats) VFS = llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(std::move(VFS)); - FileMgr = new FileManager(getFileSystemOpts(), std::move(VFS)); + FileMgr = llvm::makeIntrusiveRefCnt<FileManager>(getFileSystemOpts(), + std::move(VFS)); return FileMgr.get(); } // Source Manager void CompilerInstance::createSourceManager(FileManager &FileMgr) { - SourceMgr = new SourceManager(getDiagnostics(), FileMgr); + SourceMgr = + llvm::makeIntrusiveRefCnt<SourceManager>(getDiagnostics(), FileMgr); } // Initialize the remapping of files to alternative contents, e.g., @@ -549,11 +559,11 @@ std::string CompilerInstance::getSpecificModuleCachePath(StringRef ModuleHash) { void CompilerInstance::createASTContext() { Preprocessor &PP = getPreprocessor(); - auto *Context = new ASTContext(getLangOpts(), PP.getSourceManager(), - PP.getIdentifierTable(), PP.getSelectorTable(), - PP.getBuiltinInfo(), PP.TUKind); + auto Context = llvm::makeIntrusiveRefCnt<ASTContext>( + getLangOpts(), PP.getSourceManager(), PP.getIdentifierTable(), + PP.getSelectorTable(), PP.getBuiltinInfo(), PP.TUKind); Context->InitBuiltinTypes(getTarget(), getAuxTarget()); - setASTContext(Context); + setASTContext(std::move(Context)); } // ExternalASTSource @@ -633,17 +643,17 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource( const HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); - IntrusiveRefCntPtr<ASTReader> Reader(new ASTReader( + auto Reader = llvm::makeIntrusiveRefCnt<ASTReader>( PP, ModCache, &Context, PCHContainerRdr, CodeGenOpts, Extensions, Sysroot.empty() ? "" : Sysroot.data(), DisableValidation, AllowPCHWithCompilerErrors, /*AllowConfigurationMismatch*/ false, HSOpts.ModulesValidateSystemHeaders, HSOpts.ModulesForceValidateUserHeaders, - HSOpts.ValidateASTInputFilesContent, UseGlobalModuleIndex)); + HSOpts.ValidateASTInputFilesContent, UseGlobalModuleIndex); // We need the external source to be set up before we read the AST, because // eagerly-deserialized declarations may use it. - Context.setExternalSource(Reader.get()); + Context.setExternalSource(Reader); Reader->setDeserializationListener( static_cast<ASTDeserializationListener *>(DeserializationListener), @@ -750,7 +760,7 @@ void CompilerInstance::createSema(TranslationUnitKind TUKind, // Attach the external sema source if there is any. if (ExternalSemaSrc) { - TheSema->addExternalSource(ExternalSemaSrc.get()); + TheSema->addExternalSource(ExternalSemaSrc); ExternalSemaSrc->InitializeSema(*TheSema); } @@ -1216,9 +1226,9 @@ std::unique_ptr<CompilerInstance> CompilerInstance::cloneForModuleCompileImpl( if (ThreadSafeConfig) { Instance.createFileManager(ThreadSafeConfig->getVFS()); } else if (FrontendOpts.ModulesShareFileManager) { - Instance.setFileManager(&getFileManager()); + Instance.setFileManager(getFileManagerPtr()); } else { - Instance.createFileManager(&getVirtualFileSystem()); + Instance.createFileManager(getVirtualFileSystemPtr()); } if (ThreadSafeConfig) { @@ -1745,17 +1755,18 @@ void CompilerInstance::createASTReader() { if (timerGroup) ReadTimer = std::make_unique<llvm::Timer>("reading_modules", "Reading modules", *timerGroup); - TheASTReader = new ASTReader( + TheASTReader = llvm::makeIntrusiveRefCnt<ASTReader>( getPreprocessor(), getModuleCache(), &getASTContext(), getPCHContainerReader(), getCodeGenOpts(), getFrontendOpts().ModuleFileExtensions, Sysroot.empty() ? "" : Sysroot.c_str(), PPOpts.DisablePCHOrModuleValidation, /*AllowASTWithCompilerErrors=*/FEOpts.AllowPCMWithCompilerErrors, - /*AllowConfigurationMismatch=*/false, HSOpts.ModulesValidateSystemHeaders, - HSOpts.ModulesForceValidateUserHeaders, - HSOpts.ValidateASTInputFilesContent, - getFrontendOpts().UseGlobalModuleIndex, std::move(ReadTimer)); + /*AllowConfigurationMismatch=*/false, + +HSOpts.ModulesValidateSystemHeaders, + +HSOpts.ModulesForceValidateUserHeaders, + +HSOpts.ValidateASTInputFilesContent, + +getFrontendOpts().UseGlobalModuleIndex, std::move(ReadTimer)); if (hasASTConsumer()) { TheASTReader->setDeserializationListener( getASTConsumer().GetASTDeserializationListener()); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index ab4384a..9f77e62 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -826,7 +826,7 @@ static bool RoundTrip(ParseFn Parse, GenerateFn Generate, // Setup a dummy DiagnosticsEngine. DiagnosticOptions DummyDiagOpts; - DiagnosticsEngine DummyDiags(new DiagnosticIDs(), DummyDiagOpts); + DiagnosticsEngine DummyDiags(DiagnosticIDs::create(), DummyDiagOpts); DummyDiags.setClient(new TextDiagnosticBuffer()); // Run the first parse on the original arguments with the dummy invocation and @@ -2685,7 +2685,7 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, std::optional<DiagnosticsEngine> IgnoringDiags; if (!Diags) { IgnoringDiagOpts.emplace(); - IgnoringDiags.emplace(new DiagnosticIDs(), *IgnoringDiagOpts, + IgnoringDiags.emplace(DiagnosticIDs::create(), *IgnoringDiagOpts, new IgnoringDiagConsumer()); Diags = &*IgnoringDiags; } diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index 1d82fc7..2d69f8c 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -9,6 +9,7 @@ #include "clang/Frontend/FrontendAction.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclGroup.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/DiagnosticOptions.h" @@ -39,6 +40,7 @@ #include "clang/Serialization/ASTReader.h" #include "clang/Serialization/GlobalModuleIndex.h" #include "llvm/ADT/ScopeExit.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/BuryPointer.h" #include "llvm/Support/ErrorHandling.h" @@ -87,12 +89,25 @@ public: // reducing the granularity and making the output less useful. return; } - if (auto *DC = D->getDeclContext(); !DC || !DC->isFileContext()) { + auto *DC = D->getLexicalDeclContext(); + if (!DC || !DC->isFileContext()) { // We choose to work at namespace level to reduce complexity and the // number of cases we care about. return; } + PendingDecls.push_back(D); + if (auto *NS = dyn_cast<NamespaceDecl>(DC)) { + // Add any namespaces we have not seen before. + // Note that we filter out namespaces from DeclRead as it includes too + // all redeclarations and we only want the ones that had other used + // declarations. + while (NS && ProcessedNamespaces.insert(NS).second) { + PendingDecls.push_back(NS); + + NS = dyn_cast<NamespaceDecl>(NS->getLexicalParent()); + } + } } struct Position { @@ -141,23 +156,25 @@ public: OptionalFileEntryRef Ref; }; llvm::DenseMap<const FileEntry *, FileData> FileToRanges; + for (const Decl *D : PendingDecls) { - CharSourceRange R = SM.getExpansionRange(D->getSourceRange()); - if (!R.isValid()) - continue; + for (CharSourceRange R : getRangesToMark(D)) { + if (!R.isValid()) + continue; - auto *F = SM.getFileEntryForID(SM.getFileID(R.getBegin())); - if (F != SM.getFileEntryForID(SM.getFileID(R.getEnd()))) { - // Such cases are rare and difficult to handle. - continue; - } + auto *F = SM.getFileEntryForID(SM.getFileID(R.getBegin())); + if (F != SM.getFileEntryForID(SM.getFileID(R.getEnd()))) { + // Such cases are rare and difficult to handle. + continue; + } - auto &Data = FileToRanges[F]; - if (!Data.Ref) - Data.Ref = SM.getFileEntryRefForID(SM.getFileID(R.getBegin())); - Data.FromTo.push_back( - {Position::GetBeginSpelling(SM, R), - Position::GetEndSpelling(SM, R, D->getLangOpts())}); + auto &Data = FileToRanges[F]; + if (!Data.Ref) + Data.Ref = SM.getFileEntryRefForID(SM.getFileID(R.getBegin())); + Data.FromTo.push_back( + {Position::GetBeginSpelling(SM, R), + Position::GetEndSpelling(SM, R, D->getLangOpts())}); + } } // To simplify output, merge consecutive and intersecting ranges. @@ -188,10 +205,49 @@ public: private: std::vector<const Decl *> PendingDecls; + llvm::SmallPtrSet<const NamespaceDecl *, 0> ProcessedNamespaces; bool IsCollectingDecls = true; const SourceManager &SM; std::unique_ptr<llvm::raw_ostream> OS; + llvm::SmallVector<CharSourceRange, 2> getRangesToMark(const Decl *D) { + auto *NS = dyn_cast<NamespaceDecl>(D); + if (!NS) + return {SM.getExpansionRange(D->getSourceRange())}; + + SourceLocation LBraceLoc; + if (NS->isAnonymousNamespace()) { + LBraceLoc = NS->getLocation(); + } else { + // Start with the location of the identifier. + SourceLocation TokenBeforeLBrace = NS->getLocation(); + if (NS->hasAttrs()) { + for (auto *A : NS->getAttrs()) { + // But attributes may go after it. + if (SM.isBeforeInTranslationUnit(TokenBeforeLBrace, + A->getRange().getEnd())) { + // Give up, the attributes are often coming from macros and we + // cannot skip them reliably. + return {}; + } + } + } + auto &LangOpts = D->getLangOpts(); + // Now skip one token, the next should be the lbrace. + Token Tok; + if (Lexer::getRawToken(TokenBeforeLBrace, Tok, SM, LangOpts, true) || + Lexer::getRawToken(Tok.getEndLoc(), Tok, SM, LangOpts, true) || + Tok.getKind() != tok::l_brace) { + // On error or if we did not find the token we expected, avoid marking + // everything inside the namespace as used. + return {}; + } + LBraceLoc = Tok.getLocation(); + } + return {SM.getExpansionRange(SourceRange(NS->getBeginLoc(), LBraceLoc)), + SM.getExpansionRange(NS->getRBraceLoc())}; + } + void printJson(llvm::ArrayRef<RequiredRanges> Result) { *OS << "{\n"; *OS << R"( "required_ranges": [)" << "\n"; @@ -226,6 +282,8 @@ private: } *OS << " ]\n"; *OS << "}\n"; + + OS->flush(); } }; @@ -763,11 +821,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // If we're replaying the build of an AST file, import it and set up // the initial state from its build. if (ReplayASTFile) { - IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics()); + IntrusiveRefCntPtr<DiagnosticsEngine> Diags = CI.getDiagnosticsPtr(); // The AST unit populates its own diagnostics engine rather than ours. - IntrusiveRefCntPtr<DiagnosticsEngine> ASTDiags(new DiagnosticsEngine( - Diags->getDiagnosticIDs(), Diags->getDiagnosticOptions())); + auto ASTDiags = llvm::makeIntrusiveRefCnt<DiagnosticsEngine>( + Diags->getDiagnosticIDs(), Diags->getDiagnosticOptions()); ASTDiags->setClient(Diags->getClient(), /*OwnsClient*/false); // FIXME: What if the input is a memory buffer? @@ -787,7 +845,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // Set the shared objects, these are reset when we finish processing the // file, otherwise the CompilerInstance will happily destroy them. - CI.setFileManager(&AST->getFileManager()); + CI.setFileManager(AST->getFileManagerPtr()); CI.createSourceManager(CI.getFileManager()); CI.getSourceManager().initializeForReplay(AST->getSourceManager()); @@ -835,7 +893,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, assert(hasASTFileSupport() && "This action does not have AST file support!"); - IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics()); + IntrusiveRefCntPtr<DiagnosticsEngine> Diags = CI.getDiagnosticsPtr(); // FIXME: What if the input is a memory buffer? StringRef InputFile = Input.getFile(); @@ -854,13 +912,13 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // Set the shared objects, these are reset when we finish processing the // file, otherwise the CompilerInstance will happily destroy them. - CI.setFileManager(&AST->getFileManager()); - CI.setSourceManager(&AST->getSourceManager()); + CI.setFileManager(AST->getFileManagerPtr()); + CI.setSourceManager(AST->getSourceManagerPtr()); CI.setPreprocessor(AST->getPreprocessorPtr()); Preprocessor &PP = CI.getPreprocessor(); PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(), PP.getLangOpts()); - CI.setASTContext(&AST->getASTContext()); + CI.setASTContext(AST->getASTContextPtr()); setCurrentInput(Input, std::move(AST)); @@ -1114,11 +1172,12 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) { // Convert headers to PCH and chain them. - IntrusiveRefCntPtr<ExternalSemaSource> source, FinalReader; + IntrusiveRefCntPtr<ExternalSemaSource> source; + IntrusiveRefCntPtr<ASTReader> FinalReader; source = createChainedIncludesSource(CI, FinalReader); if (!source) return false; - CI.setASTReader(static_cast<ASTReader *>(FinalReader.get())); + CI.setASTReader(FinalReader); CI.getASTContext().setExternalSource(source); } else if (CI.getLangOpts().Modules || !CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { @@ -1194,23 +1253,21 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // provides the layouts from that file. if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() && CI.hasASTContext() && !CI.getASTContext().getExternalSource()) { - IntrusiveRefCntPtr<ExternalASTSource> - Override(new LayoutOverrideSource( - CI.getFrontendOpts().OverrideRecordLayoutsFile)); + auto Override = llvm::makeIntrusiveRefCnt<LayoutOverrideSource>( + CI.getFrontendOpts().OverrideRecordLayoutsFile); CI.getASTContext().setExternalSource(Override); } // Setup HLSL External Sema Source if (CI.getLangOpts().HLSL && CI.hasASTContext()) { - IntrusiveRefCntPtr<ExternalSemaSource> HLSLSema( - new HLSLExternalSemaSource()); - if (auto *SemaSource = dyn_cast_if_present<ExternalSemaSource>( - CI.getASTContext().getExternalSource())) { - IntrusiveRefCntPtr<ExternalSemaSource> MultiSema( - new MultiplexExternalSemaSource(SemaSource, HLSLSema.get())); - CI.getASTContext().setExternalSource(MultiSema); + auto HLSLSema = llvm::makeIntrusiveRefCnt<HLSLExternalSemaSource>(); + if (auto SemaSource = dyn_cast_if_present<ExternalSemaSource>( + CI.getASTContext().getExternalSourcePtr())) { + auto MultiSema = llvm::makeIntrusiveRefCnt<MultiplexExternalSemaSource>( + std::move(SemaSource), std::move(HLSLSema)); + CI.getASTContext().setExternalSource(std::move(MultiSema)); } else - CI.getASTContext().setExternalSource(HLSLSema); + CI.getASTContext().setExternalSource(std::move(HLSLSema)); } FailureCleanup.release(); diff --git a/clang/lib/Frontend/PrecompiledPreamble.cpp b/clang/lib/Frontend/PrecompiledPreamble.cpp index 146cf90..03f70b7 100644 --- a/clang/lib/Frontend/PrecompiledPreamble.cpp +++ b/clang/lib/Frontend/PrecompiledPreamble.cpp @@ -57,11 +57,9 @@ createVFSOverlayForPreamblePCH(StringRef PCHFilename, IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) { // We want only the PCH file from the real filesystem to be available, // so we create an in-memory VFS with just that and overlay it on top. - IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> PCHFS( - new llvm::vfs::InMemoryFileSystem()); + auto PCHFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); PCHFS->addFile(PCHFilename, 0, std::move(PCHBuffer)); - IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> Overlay( - new llvm::vfs::OverlayFileSystem(VFS)); + auto Overlay = llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(VFS); Overlay->pushOverlay(PCHFS); return Overlay; } @@ -414,7 +412,7 @@ PrecompiledPreamble::operator=(PrecompiledPreamble &&) = default; llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build( const CompilerInvocation &Invocation, const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, - DiagnosticsEngine &Diagnostics, + IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics, IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, std::shared_ptr<PCHContainerOperations> PCHContainerOps, bool StoreInMemory, StringRef StoragePath, PreambleCallbacks &Callbacks) { @@ -463,7 +461,7 @@ llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build( llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup( Clang.get()); - Clang->setDiagnostics(&Diagnostics); + Clang->setDiagnostics(Diagnostics); // Create the target instance. if (!Clang->createTarget()) @@ -478,18 +476,19 @@ llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build( } // Clear out old caches and data. - Diagnostics.Reset(); - ProcessWarningOptions(Diagnostics, Clang->getDiagnosticOpts(), *VFS); + Diagnostics->Reset(); + ProcessWarningOptions(*Diagnostics, Clang->getDiagnosticOpts(), *VFS); - VFS = - createVFSFromCompilerInvocation(Clang->getInvocation(), Diagnostics, VFS); + VFS = createVFSFromCompilerInvocation(Clang->getInvocation(), *Diagnostics, + VFS); // Create a file manager object to provide access to and cache the filesystem. - Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS)); + Clang->setFileManager( + llvm::makeIntrusiveRefCnt<FileManager>(Clang->getFileSystemOpts(), VFS)); // Create the source manager. - Clang->setSourceManager( - new SourceManager(Diagnostics, Clang->getFileManager())); + Clang->setSourceManager(llvm::makeIntrusiveRefCnt<SourceManager>( + *Diagnostics, Clang->getFileManager())); auto PreambleDepCollector = std::make_shared<PreambleDependencyCollector>(); Clang->addDependencyCollector(PreambleDepCollector); diff --git a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp index 23a1f90..1f5bb47 100644 --- a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp +++ b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp @@ -753,10 +753,9 @@ DiagnosticsEngine *SDiagsWriter::getMetaDiags() { // to be distinct from the engine the writer was being added to and would // normally not be used. if (!State->MetaDiagnostics) { - IntrusiveRefCntPtr<DiagnosticIDs> IDs(new DiagnosticIDs()); auto Client = new TextDiagnosticPrinter(llvm::errs(), State->DiagOpts); - State->MetaDiagnostics = - std::make_unique<DiagnosticsEngine>(IDs, State->DiagOpts, Client); + State->MetaDiagnostics = std::make_unique<DiagnosticsEngine>( + DiagnosticIDs::create(), State->DiagOpts, Client); } return State->MetaDiagnostics.get(); } diff --git a/clang/lib/Headers/__clang_cuda_runtime_wrapper.h b/clang/lib/Headers/__clang_cuda_runtime_wrapper.h index 44934ba..b1e5924 100644 --- a/clang/lib/Headers/__clang_cuda_runtime_wrapper.h +++ b/clang/lib/Headers/__clang_cuda_runtime_wrapper.h @@ -385,7 +385,12 @@ __host__ __device__ void __nv_tex_surf_handler(const char *name, T *ptr, #endif // CUDA_VERSION #endif // __cplusplus >= 201103L && CUDA_VERSION >= 9000 #include "surface_indirect_functions.h" +#if CUDA_VERSION < 13000 +// Direct texture fetch functions had been deprecated since CUDA-11. +// The file in CUDA-12 only carried unused texture types, and is no longer +// needed. #include "texture_fetch_functions.h" +#endif // CUDA_VERSION < 13000 #include "texture_indirect_functions.h" // Restore state of __CUDA_ARCH__ and __THROW we had on entry. diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h index e8ccccb..c877234 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h @@ -12,7 +12,7 @@ namespace hlsl { namespace __detail { -constexpr vector<uint, 4> d3d_color_to_ubyte4_impl(vector<float, 4> V) { +constexpr int4 d3d_color_to_ubyte4_impl(float4 V) { // Use the same scaling factor used by FXC, and DXC for DXIL // (i.e., 255.001953) // https://github.com/microsoft/DirectXShaderCompiler/blob/070d0d5a2beacef9eeb51037a9b04665716fd6f3/lib/HLSL/HLOperationLower.cpp#L666C1-L697C2 diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 499a053..d9d87c8 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -418,7 +418,7 @@ const inline float4 lit(float NDotL, float NDotH, float M) { /// This function swizzles and scales components of the \a x parameter. Use this /// function to compensate for the lack of UBYTE4 support in some hardware. -constexpr vector<uint, 4> D3DCOLORtoUBYTE4(vector<float, 4> V) { +constexpr int4 D3DCOLORtoUBYTE4(float4 V) { return __detail::d3d_color_to_ubyte4_impl(V); } diff --git a/clang/lib/Interpreter/CodeCompletion.cpp b/clang/lib/Interpreter/CodeCompletion.cpp index dac3888..dc7030c 100644 --- a/clang/lib/Interpreter/CodeCompletion.cpp +++ b/clang/lib/Interpreter/CodeCompletion.cpp @@ -238,11 +238,9 @@ public: // compiler instance before the super `ExecuteAction` triggers parsing void IncrementalSyntaxOnlyAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); - ExternalSource *myExternalSource = - new ExternalSource(CI.getASTContext(), CI.getFileManager(), - ParentCI->getASTContext(), ParentCI->getFileManager()); - llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> astContextExternalSource( - myExternalSource); + auto astContextExternalSource = llvm::makeIntrusiveRefCnt<ExternalSource>( + CI.getASTContext(), CI.getFileManager(), ParentCI->getASTContext(), + ParentCI->getFileManager()); CI.getASTContext().setExternalSource(astContextExternalSource); CI.getASTContext().getTranslationUnitDecl()->setHasExternalVisibleStorage( true); @@ -380,9 +378,9 @@ void ReplCodeCompleter::codeComplete(CompilerInstance *InterpCI, AU->setOwnsRemappedFileBuffers(false); AU->CodeComplete(CodeCompletionFileName, 1, Col, RemappedFiles, false, false, false, consumer, - std::make_shared<clang::PCHContainerOperations>(), *diag, - InterpCI->getLangOpts(), AU->getSourceManager(), - AU->getFileManager(), sd, tb, std::move(Act)); + std::make_shared<clang::PCHContainerOperations>(), diag, + InterpCI->getLangOpts(), AU->getSourceManagerPtr(), + AU->getFileManagerPtr(), sd, tb, std::move(Act)); } } // namespace clang diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index 9b71486..5e5ae81 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -86,7 +86,6 @@ GetCC1Arguments(DiagnosticsEngine *Diagnostics, static llvm::Expected<std::unique_ptr<CompilerInstance>> CreateCI(const llvm::opt::ArgStringList &Argv) { std::unique_ptr<CompilerInstance> Clang(new CompilerInstance()); - IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); // Register the support for object-file-wrapped Clang modules. // FIXME: Clang should register these container operations automatically. @@ -98,7 +97,7 @@ CreateCI(const llvm::opt::ArgStringList &Argv) { // a well formed diagnostic object. DiagnosticOptions DiagOpts; TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer; - DiagnosticsEngine Diags(DiagID, DiagOpts, DiagsBuffer); + DiagnosticsEngine Diags(DiagnosticIDs::create(), DiagOpts, DiagsBuffer); bool Success = CompilerInvocation::CreateFromArgs( Clang->getInvocation(), llvm::ArrayRef(Argv.begin(), Argv.size()), Diags); @@ -174,11 +173,10 @@ IncrementalCompilerBuilder::create(std::string TT, // Buffer diagnostics from argument parsing so that we can output them using a // well formed diagnostic object. - IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); std::unique_ptr<DiagnosticOptions> DiagOpts = CreateAndPopulateDiagOpts(ClangArgv); TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer; - DiagnosticsEngine Diags(DiagID, *DiagOpts, DiagsBuffer); + DiagnosticsEngine Diags(DiagnosticIDs::create(), *DiagOpts, DiagsBuffer); driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0], TT, Diags); Driver.setCheckInputsExist(false); // the input comes from mem buffers diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 829c81b..35ad0b5 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -503,8 +503,12 @@ static bool areAllValuesNoReturn(const VarDecl *VD, const CFGBlock &VarBlk, TransferFunctions TF(VD); BackwardDataflowWorklist Worklist(*AC.getCFG(), AC); + llvm::DenseSet<const CFGBlock *> Visited; Worklist.enqueueBlock(&VarBlk); while (const CFGBlock *B = Worklist.dequeue()) { + if (Visited.contains(B)) + continue; + Visited.insert(B); // First check the current block. for (CFGBlock::const_reverse_iterator ri = B->rbegin(), re = B->rend(); ri != re; ++ri) { diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp index fbfb242..1f040c8 100644 --- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -20,26 +20,19 @@ char MultiplexExternalSemaSource::ID; /// given element to it. /// MultiplexExternalSemaSource::MultiplexExternalSemaSource( - ExternalSemaSource *S1, ExternalSemaSource *S2) { - S1->Retain(); - S2->Retain(); - Sources.push_back(S1); - Sources.push_back(S2); -} - -// pin the vtable here. -MultiplexExternalSemaSource::~MultiplexExternalSemaSource() { - for (auto *S : Sources) - S->Release(); + llvm::IntrusiveRefCntPtr<ExternalSemaSource> S1, + llvm::IntrusiveRefCntPtr<ExternalSemaSource> S2) { + Sources.push_back(std::move(S1)); + Sources.push_back(std::move(S2)); } /// Appends new source to the source list. /// ///\param[in] source - An ExternalSemaSource. /// -void MultiplexExternalSemaSource::AddSource(ExternalSemaSource *Source) { - Source->Retain(); - Sources.push_back(Source); +void MultiplexExternalSemaSource::AddSource( + llvm::IntrusiveRefCntPtr<ExternalSemaSource> Source) { + Sources.push_back(std::move(Source)); } //===----------------------------------------------------------------------===// @@ -92,7 +85,7 @@ CXXBaseSpecifier *MultiplexExternalSemaSource::GetExternalCXXBaseSpecifiers( CXXCtorInitializer ** MultiplexExternalSemaSource::GetExternalCXXCtorInitializers(uint64_t Offset) { - for (auto *S : Sources) + for (auto &S : Sources) if (auto *R = S->GetExternalCXXCtorInitializers(Offset)) return R; return nullptr; @@ -371,6 +364,6 @@ bool MultiplexExternalSemaSource::MaybeDiagnoseMissingCompleteType( void MultiplexExternalSemaSource::AssignedLambdaNumbering( CXXRecordDecl *Lambda) { - for (auto *Source : Sources) + for (auto &Source : Sources) Source->AssignedLambdaNumbering(Lambda); } diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index d50eeff..924becf 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -656,18 +656,19 @@ ASTMutationListener *Sema::getASTMutationListener() const { return getASTConsumer().GetASTMutationListener(); } -void Sema::addExternalSource(ExternalSemaSource *E) { +void Sema::addExternalSource(IntrusiveRefCntPtr<ExternalSemaSource> E) { assert(E && "Cannot use with NULL ptr"); if (!ExternalSource) { - ExternalSource = E; + ExternalSource = std::move(E); return; } - if (auto *Ex = dyn_cast<MultiplexExternalSemaSource>(ExternalSource)) - Ex->AddSource(E); + if (auto *Ex = dyn_cast<MultiplexExternalSemaSource>(ExternalSource.get())) + Ex->AddSource(std::move(E)); else - ExternalSource = new MultiplexExternalSemaSource(ExternalSource.get(), E); + ExternalSource = llvm::makeIntrusiveRefCnt<MultiplexExternalSemaSource>( + ExternalSource, std::move(E)); } void Sema::PrintStats() const { @@ -2251,16 +2252,15 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { } // Don't allow SVE types in functions without a SVE target. - if (Ty->isSVESizelessBuiltinType() && FD) { + if (Ty->isSVESizelessBuiltinType() && FD && !FD->getType().isNull()) { llvm::StringMap<bool> CallerFeatureMap; Context.getFunctionFeatureMap(CallerFeatureMap, FD); if (!Builtin::evaluateRequiredTargetFeatures("sve", CallerFeatureMap)) { if (!Builtin::evaluateRequiredTargetFeatures("sme", CallerFeatureMap)) Diag(Loc, diag::err_sve_vector_in_non_sve_target) << Ty; else if (!IsArmStreamingFunction(FD, - /*IncludeLocallyStreaming=*/true)) { + /*IncludeLocallyStreaming=*/true)) Diag(Loc, diag::err_sve_vector_in_non_streaming_function) << Ty; - } } } diff --git a/clang/lib/Sema/SemaAMDGPU.cpp b/clang/lib/Sema/SemaAMDGPU.cpp index c23c98a..a5fbd70 100644 --- a/clang/lib/Sema/SemaAMDGPU.cpp +++ b/clang/lib/Sema/SemaAMDGPU.cpp @@ -84,6 +84,22 @@ bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, return checkMovDPPFunctionCall(TheCall, 2, 1); case AMDGPU::BI__builtin_amdgcn_update_dpp: { return checkMovDPPFunctionCall(TheCall, 6, 2); + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk8_f16_fp8: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk8_bf16_fp8: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk8_f16_bf8: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk8_bf16_bf8: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk8_f16_fp4: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk8_bf16_fp4: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk8_f32_fp8: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk8_f32_bf8: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk8_f32_fp4: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_f16_fp6: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_bf16_fp6: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_f16_bf6: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_bf16_bf6: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_f32_fp6: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_f32_bf6: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 7); } default: return false; diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index c74b671..bc87611 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -15893,9 +15893,7 @@ ExprResult Sema::BuiltinMatrixTranspose(CallExpr *TheCall, // Get and verify the matrix dimensions. static std::optional<unsigned> getAndVerifyMatrixDimension(Expr *Expr, StringRef Name, Sema &S) { - SourceLocation ErrorPos; - std::optional<llvm::APSInt> Value = - Expr->getIntegerConstantExpr(S.Context, &ErrorPos); + std::optional<llvm::APSInt> Value = Expr->getIntegerConstantExpr(S.Context); if (!Value) { S.Diag(Expr->getBeginLoc(), diag::err_builtin_matrix_scalar_unsigned_arg) << Name; diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index a43ac9e..0de5580 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -4034,6 +4034,14 @@ static void AddOverloadParameterChunks( return; } + // C++23 introduces an explicit object parameter, a.k.a. "deducing this" + // Skip it for autocomplete and treat the next parameter as the first + // parameter + if (Function && FirstParameter && + Function->getParamDecl(P)->isExplicitObjectParameter()) { + continue; + } + if (FirstParameter) FirstParameter = false; else diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index c7e7507..e2ac648 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3063,7 +3063,8 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { // error since the definition will have already been created without // the semantic effects of the attribute having been applied. S.Diag(NewAttribute->getLocation(), - diag::err_sycl_entry_point_after_definition); + diag::err_sycl_entry_point_after_definition) + << NewAttribute; S.Diag(Def->getLocation(), diag::note_previous_definition); cast<SYCLKernelEntryPointAttr>(NewAttribute)->setInvalidAttr(); ++I; @@ -14723,9 +14724,9 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { type->isIntegralOrEnumerationType()) { // In C++98, in-class initialization for a static data member must // be an integer constant expression. - SourceLocation Loc; - if (!Init->isIntegerConstantExpr(Context, &Loc)) { - Diag(Loc, diag::ext_in_class_initializer_non_constant) + if (!Init->isIntegerConstantExpr(Context)) { + Diag(Init->getExprLoc(), + diag::ext_in_class_initializer_non_constant) << Init->getSourceRange(); } } @@ -16258,19 +16259,19 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, FD->getAttr<SYCLKernelEntryPointAttr>(); if (FD->isDefaulted()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*defaulted function*/ 3; + << SKEPAttr << /*defaulted function*/ 3; SKEPAttr->setInvalidAttr(); } else if (FD->isDeleted()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*deleted function*/ 2; + << SKEPAttr << /*deleted function*/ 2; SKEPAttr->setInvalidAttr(); } else if (FSI->isCoroutine()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*coroutine*/ 7; + << SKEPAttr << /*coroutine*/ 7; SKEPAttr->setInvalidAttr(); } else if (Body && isa<CXXTryStmt>(Body)) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*function defined with a function try block*/ 8; + << SKEPAttr << /*function defined with a function try block*/ 8; SKEPAttr->setInvalidAttr(); } diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 3e03cb4..4683c81 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -262,12 +262,13 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { if (!getASTContext().hasSameType(SAI->getKernelName(), SKEPAttr->getKernelName())) { Diag(SAI->getLocation(), diag::err_sycl_entry_point_invalid_redeclaration) - << SAI->getKernelName() << SKEPAttr->getKernelName(); + << SKEPAttr << SAI->getKernelName() << SKEPAttr->getKernelName(); Diag(SKEPAttr->getLocation(), diag::note_previous_attribute); SAI->setInvalidAttr(); } else { Diag(SAI->getLocation(), - diag::warn_sycl_entry_point_redundant_declaration); + diag::warn_sycl_entry_point_redundant_declaration) + << SAI; Diag(SKEPAttr->getLocation(), diag::note_previous_attribute); } } @@ -289,7 +290,8 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { PrevSKEPAttr->getKernelName())) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid_redeclaration) - << SKEPAttr->getKernelName() << PrevSKEPAttr->getKernelName(); + << SKEPAttr << SKEPAttr->getKernelName() + << PrevSKEPAttr->getKernelName(); Diag(PrevSKEPAttr->getLocation(), diag::note_previous_decl) << PrevFD; SKEPAttr->setInvalidAttr(); } @@ -299,50 +301,52 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) { if (!MD->isStatic()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*non-static member function*/ 0; + << SKEPAttr << /*non-static member function*/ 0; SKEPAttr->setInvalidAttr(); } } if (FD->isVariadic()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*variadic function*/ 1; + << SKEPAttr << /*variadic function*/ 1; SKEPAttr->setInvalidAttr(); } if (FD->isDefaulted()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*defaulted function*/ 3; + << SKEPAttr << /*defaulted function*/ 3; SKEPAttr->setInvalidAttr(); } else if (FD->isDeleted()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*deleted function*/ 2; + << SKEPAttr << /*deleted function*/ 2; SKEPAttr->setInvalidAttr(); } if (FD->isConsteval()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*consteval function*/ 5; + << SKEPAttr << /*consteval function*/ 5; SKEPAttr->setInvalidAttr(); } else if (FD->isConstexpr()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*constexpr function*/ 4; + << SKEPAttr << /*constexpr function*/ 4; SKEPAttr->setInvalidAttr(); } if (FD->isNoReturn()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*function declared with the 'noreturn' attribute*/ 6; + << SKEPAttr << /*function declared with the 'noreturn' attribute*/ 6; SKEPAttr->setInvalidAttr(); } if (FD->getReturnType()->isUndeducedType()) { Diag(SKEPAttr->getLocation(), - diag::err_sycl_entry_point_deduced_return_type); + diag::err_sycl_entry_point_deduced_return_type) + << SKEPAttr; SKEPAttr->setInvalidAttr(); } else if (!FD->getReturnType()->isDependentType() && !FD->getReturnType()->isVoidType()) { - Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_return_type); + Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_return_type) + << SKEPAttr; SKEPAttr->setInvalidAttr(); } @@ -354,7 +358,8 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { if (!declaresSameEntity(FD, SKI->getKernelEntryPointDecl())) { // FIXME: This diagnostic should include the origin of the kernel // FIXME: names; not just the locations of the conflicting declarations. - Diag(FD->getLocation(), diag::err_sycl_kernel_name_conflict); + Diag(FD->getLocation(), diag::err_sycl_kernel_name_conflict) + << SKEPAttr; Diag(SKI->getKernelEntryPointDecl()->getLocation(), diag::note_previous_declaration); SKEPAttr->setInvalidAttr(); diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 572dbf2..b0a673d 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -1387,7 +1387,8 @@ static void CheckFoldOperand(Sema &S, Expr *E) { S.Diag(E->getExprLoc(), diag::err_fold_expression_bad_operand) << E->getSourceRange() << FixItHint::CreateInsertion(E->getBeginLoc(), "(") - << FixItHint::CreateInsertion(E->getEndLoc(), ")"); + << FixItHint::CreateInsertion(S.getLocForEndOfToken(E->getEndLoc()), + ")"); } } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index f896f9f1..682d263 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -677,8 +677,7 @@ bool PCHValidator::ReadDiagnosticOptions(DiagnosticOptions &DiagOpts, bool Complain) { DiagnosticsEngine &ExistingDiags = PP.getDiagnostics(); IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(ExistingDiags.getDiagnosticIDs()); - IntrusiveRefCntPtr<DiagnosticsEngine> Diags( - new DiagnosticsEngine(DiagIDs, DiagOpts)); + auto Diags = llvm::makeIntrusiveRefCnt<DiagnosticsEngine>(DiagIDs, DiagOpts); // This should never fail, because we would have processed these options // before writing them to an ASTFile. ProcessWarningOptions(*Diags, DiagOpts, diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index bd84a97..cdaf38d 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -1147,7 +1147,8 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { const SYCLKernelInfo *SKI = C.findSYCLKernelInfo(SKEPAttr->getKernelName()); if (SKI) { if (!declaresSameEntity(FD, SKI->getKernelEntryPointDecl())) { - Reader.Diag(FD->getLocation(), diag::err_sycl_kernel_name_conflict); + Reader.Diag(FD->getLocation(), diag::err_sycl_kernel_name_conflict) + << SKEPAttr; Reader.Diag(SKI->getKernelEntryPointDecl()->getLocation(), diag::note_previous_declaration); SKEPAttr->setInvalidAttr(); diff --git a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index 88feb6a..e682c4e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -99,7 +99,7 @@ class NilArgChecker : public Checker<check::PreObjCMessage, check::PostStmt<ObjCDictionaryLiteral>, check::PostStmt<ObjCArrayLiteral>, EventDispatcher<ImplicitNullDerefEvent>> { - mutable std::unique_ptr<APIMisuse> BT; + const APIMisuse BT{this, "nil argument"}; mutable llvm::SmallDenseMap<Selector, unsigned, 16> StringSelectors; mutable Selector ArrayWithObjectSel; @@ -218,10 +218,7 @@ void NilArgChecker::generateBugReport(ExplodedNode *N, SourceRange Range, const Expr *E, CheckerContext &C) const { - if (!BT) - BT.reset(new APIMisuse(this, "nil argument")); - - auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N); + auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N); R->addRange(Range); bugreporter::trackExpressionValue(N, E, *R); C.emitReport(std::move(R)); @@ -350,7 +347,7 @@ void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL, namespace { class CFNumberChecker : public Checker< check::PreStmt<CallExpr> > { - mutable std::unique_ptr<APIMisuse> BT; + const APIMisuse BT{this, "Bad use of CFNumber APIs"}; mutable IdentifierInfo *ICreate = nullptr, *IGetValue = nullptr; public: CFNumberChecker() = default; @@ -524,10 +521,7 @@ void CFNumberChecker::checkPreStmt(const CallExpr *CE, << " bits of the integer value will be " << (isCreate ? "lost." : "garbage."); - if (!BT) - BT.reset(new APIMisuse(this, "Bad use of CFNumber APIs")); - - auto report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N); + auto report = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N); report->addRange(CE->getArg(2)->getSourceRange()); C.emitReport(std::move(report)); } @@ -539,7 +533,7 @@ void CFNumberChecker::checkPreStmt(const CallExpr *CE, namespace { class CFRetainReleaseChecker : public Checker<check::PreCall> { - mutable APIMisuse BT{this, "null passed to CF memory management function"}; + const APIMisuse BT{this, "null passed to CF memory management function"}; const CallDescriptionSet ModelledCalls = { {CDM::CLibrary, {"CFRetain"}, 1}, {CDM::CLibrary, {"CFRelease"}, 1}, @@ -600,7 +594,8 @@ class ClassReleaseChecker : public Checker<check::PreObjCMessage> { mutable Selector retainS; mutable Selector autoreleaseS; mutable Selector drainS; - mutable std::unique_ptr<BugType> BT; + const APIMisuse BT{ + this, "message incorrectly sent to class instead of class instance"}; public: void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const; @@ -609,10 +604,7 @@ public: void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const { - if (!BT) { - BT.reset(new APIMisuse( - this, "message incorrectly sent to class instead of class instance")); - + if (releaseS.isNull()) { ASTContext &Ctx = C.getASTContext(); releaseS = GetNullarySelector("release", Ctx); retainS = GetNullarySelector("retain", Ctx); @@ -639,7 +631,7 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg, "of class '" << Class->getName() << "' and not the class directly"; - auto report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N); + auto report = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N); report->addRange(msg.getSourceRange()); C.emitReport(std::move(report)); } @@ -658,7 +650,8 @@ class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> { mutable Selector orderedSetWithObjectsS; mutable Selector initWithObjectsS; mutable Selector initWithObjectsAndKeysS; - mutable std::unique_ptr<BugType> BT; + const APIMisuse BT{this, "Arguments passed to variadic method aren't all " + "Objective-C pointer types"}; bool isVariadicMessage(const ObjCMethodCall &msg) const; @@ -717,11 +710,7 @@ VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const { void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const { - if (!BT) { - BT.reset(new APIMisuse(this, - "Arguments passed to variadic method aren't all " - "Objective-C pointer types")); - + if (arrayWithObjectsS.isNull()) { ASTContext &Ctx = C.getASTContext(); arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx); dictionaryWithObjectsAndKeysS = @@ -792,8 +781,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg, ArgTy.print(os, C.getLangOpts()); os << "'"; - auto R = - std::make_unique<PathSensitiveBugReport>(*BT, os.str(), *errorNode); + auto R = std::make_unique<PathSensitiveBugReport>(BT, os.str(), *errorNode); R->addRange(msg.getArgSourceRange(I)); C.emitReport(std::move(R)); } diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 31cb150..fd0a398 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -78,35 +78,30 @@ static QualType getCharPtrType(ASTContext &Ctx, CharKind CK) { : Ctx.WideCharTy); } -class CStringChecker : public Checker< eval::Call, - check::PreStmt<DeclStmt>, - check::LiveSymbols, - check::DeadSymbols, - check::RegionChanges - > { - mutable std::unique_ptr<BugType> BT_Null, BT_Bounds, BT_Overlap, - BT_NotCString, BT_AdditionOverflow, BT_UninitRead; - +class CStringChecker + : public CheckerFamily<eval::Call, check::PreStmt<DeclStmt>, + check::LiveSymbols, check::DeadSymbols, + check::RegionChanges> { mutable const char *CurrentFunctionDescription = nullptr; public: - /// The filter is used to filter out the diagnostics which are not enabled by - /// the user. - struct CStringChecksFilter { - bool CheckCStringNullArg = false; - bool CheckCStringOutOfBounds = false; - bool CheckCStringBufferOverlap = false; - bool CheckCStringNotNullTerm = false; - bool CheckCStringUninitializedRead = false; - - CheckerNameRef CheckNameCStringNullArg; - CheckerNameRef CheckNameCStringOutOfBounds; - CheckerNameRef CheckNameCStringBufferOverlap; - CheckerNameRef CheckNameCStringNotNullTerm; - CheckerNameRef CheckNameCStringUninitializedRead; - }; - - CStringChecksFilter Filter; + // FIXME: The bug types emitted by this checker family have confused garbage + // in their Description and Category fields (e.g. `categories::UnixAPI` is + // passed as the description in several cases and `uninitialized` is mistyped + // as `unitialized`). This should be cleaned up. + CheckerFrontendWithBugType NullArg{categories::UnixAPI}; + CheckerFrontendWithBugType OutOfBounds{"Out-of-bound array access"}; + CheckerFrontendWithBugType BufferOverlap{categories::UnixAPI, + "Improper arguments"}; + CheckerFrontendWithBugType NotNullTerm{categories::UnixAPI}; + CheckerFrontendWithBugType UninitializedRead{ + "Accessing unitialized/garbage values"}; + + // FIXME: This bug type should be removed because it is only emitted in a + // situation that is practically impossible. + const BugType AdditionOverflow{&OutOfBounds, "API"}; + + StringRef getDebugTag() const override { return "MallocChecker"; } static void *getTag() { static int tag; return &tag; } @@ -384,7 +379,7 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C, assumeZero(C, State, l, Arg.Expression->getType()); if (stateNull && !stateNonNull) { - if (Filter.CheckCStringNullArg) { + if (NullArg.isEnabled()) { SmallString<80> buf; llvm::raw_svector_ostream OS(buf); assert(CurrentFunctionDescription); @@ -468,7 +463,7 @@ ProgramStateRef CStringChecker::checkInit(CheckerContext &C, return State; // Ensure that we wouldn't read uninitialized value. - if (Filter.CheckCStringUninitializedRead && + if (UninitializedRead.isEnabled() && State->getSVal(*FirstElementVal).isUndef()) { llvm::SmallString<258> Buf; llvm::raw_svector_ostream OS(Buf); @@ -524,7 +519,7 @@ ProgramStateRef CStringChecker::checkInit(CheckerContext &C, if (!isa<Loc>(LastElementVal)) return State; - if (Filter.CheckCStringUninitializedRead && + if (UninitializedRead.isEnabled() && State->getSVal(LastElementVal.castAs<Loc>()).isUndef()) { const llvm::APSInt *IdxInt = LastIdx.getAsInteger(); // If we can't get emit a sensible last element index, just bail out -- @@ -581,13 +576,9 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C, auto [StInBound, StOutBound] = state->assumeInBoundDual(*Idx, Size); if (StOutBound && !StInBound) { - // These checks are either enabled by the CString out-of-bounds checker - // explicitly or implicitly by the Malloc checker. - // In the latter case we only do modeling but do not emit warning. - if (!Filter.CheckCStringOutOfBounds) + if (!OutOfBounds.isEnabled()) return nullptr; - // Emit a bug report. ErrorMessage Message = createOutOfBoundErrorMsg(CurrentFunctionDescription, Access); emitOutOfBoundsBug(C, StOutBound, Buffer.Expression, Message); @@ -620,7 +611,7 @@ CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State, return nullptr; // If out-of-bounds checking is turned off, skip the rest. - if (!Filter.CheckCStringOutOfBounds) + if (!OutOfBounds.isEnabled()) return State; SVal BufStart = @@ -670,7 +661,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C, SizeArgExpr Size, AnyArgExpr First, AnyArgExpr Second, CharKind CK) const { - if (!Filter.CheckCStringBufferOverlap) + if (!BufferOverlap.isEnabled()) return state; // Do a simple check for overlap: if the two arguments are from the same @@ -789,13 +780,9 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state, if (!N) return; - if (!BT_Overlap) - BT_Overlap.reset(new BugType(Filter.CheckNameCStringBufferOverlap, - categories::UnixAPI, "Improper arguments")); - // Generate a report for this bug. auto report = std::make_unique<PathSensitiveBugReport>( - *BT_Overlap, "Arguments must not be overlapping buffers", N); + BufferOverlap, "Arguments must not be overlapping buffers", N); report->addRange(First->getSourceRange()); report->addRange(Second->getSourceRange()); @@ -805,15 +792,8 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state, void CStringChecker::emitNullArgBug(CheckerContext &C, ProgramStateRef State, const Stmt *S, StringRef WarningMsg) const { if (ExplodedNode *N = C.generateErrorNode(State)) { - if (!BT_Null) { - // FIXME: This call uses the string constant 'categories::UnixAPI' as the - // description of the bug; it should be replaced by a real description. - BT_Null.reset( - new BugType(Filter.CheckNameCStringNullArg, categories::UnixAPI)); - } - auto Report = - std::make_unique<PathSensitiveBugReport>(*BT_Null, WarningMsg, N); + std::make_unique<PathSensitiveBugReport>(NullArg, WarningMsg, N); Report->addRange(S->getSourceRange()); if (const auto *Ex = dyn_cast<Expr>(S)) bugreporter::trackExpressionValue(N, Ex, *Report); @@ -826,12 +806,8 @@ void CStringChecker::emitUninitializedReadBug(CheckerContext &C, const Expr *E, const MemRegion *R, StringRef Msg) const { if (ExplodedNode *N = C.generateErrorNode(State)) { - if (!BT_UninitRead) - BT_UninitRead.reset(new BugType(Filter.CheckNameCStringUninitializedRead, - "Accessing unitialized/garbage values")); - auto Report = - std::make_unique<PathSensitiveBugReport>(*BT_UninitRead, Msg, N); + std::make_unique<PathSensitiveBugReport>(UninitializedRead, Msg, N); Report->addNote("Other elements might also be undefined", Report->getLocation()); Report->addRange(E->getSourceRange()); @@ -845,17 +821,11 @@ void CStringChecker::emitOutOfBoundsBug(CheckerContext &C, ProgramStateRef State, const Stmt *S, StringRef WarningMsg) const { if (ExplodedNode *N = C.generateErrorNode(State)) { - if (!BT_Bounds) - BT_Bounds.reset(new BugType(Filter.CheckCStringOutOfBounds - ? Filter.CheckNameCStringOutOfBounds - : Filter.CheckNameCStringNullArg, - "Out-of-bound array access")); - // FIXME: It would be nice to eventually make this diagnostic more clear, // e.g., by referencing the original declaration or by saying *why* this // reference is outside the range. auto Report = - std::make_unique<PathSensitiveBugReport>(*BT_Bounds, WarningMsg, N); + std::make_unique<PathSensitiveBugReport>(OutOfBounds, WarningMsg, N); Report->addRange(S->getSourceRange()); C.emitReport(std::move(Report)); } @@ -865,15 +835,8 @@ void CStringChecker::emitNotCStringBug(CheckerContext &C, ProgramStateRef State, const Stmt *S, StringRef WarningMsg) const { if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) { - if (!BT_NotCString) { - // FIXME: This call uses the string constant 'categories::UnixAPI' as the - // description of the bug; it should be replaced by a real description. - BT_NotCString.reset( - new BugType(Filter.CheckNameCStringNotNullTerm, categories::UnixAPI)); - } - auto Report = - std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N); + std::make_unique<PathSensitiveBugReport>(NotNullTerm, WarningMsg, N); Report->addRange(S->getSourceRange()); C.emitReport(std::move(Report)); @@ -883,14 +846,6 @@ void CStringChecker::emitNotCStringBug(CheckerContext &C, ProgramStateRef State, void CStringChecker::emitAdditionOverflowBug(CheckerContext &C, ProgramStateRef State) const { if (ExplodedNode *N = C.generateErrorNode(State)) { - if (!BT_AdditionOverflow) { - // FIXME: This call uses the word "API" as the description of the bug; - // it should be replaced by a better error message (if this unlikely - // situation continues to exist as a separate bug type). - BT_AdditionOverflow.reset( - new BugType(Filter.CheckNameCStringOutOfBounds, "API")); - } - // This isn't a great error message, but this should never occur in real // code anyway -- you'd have to create a buffer longer than a size_t can // represent, which is sort of a contradiction. @@ -898,7 +853,7 @@ void CStringChecker::emitAdditionOverflowBug(CheckerContext &C, "This expression will create a string whose length is too big to " "be represented as a size_t"; - auto Report = std::make_unique<PathSensitiveBugReport>(*BT_AdditionOverflow, + auto Report = std::make_unique<PathSensitiveBugReport>(AdditionOverflow, WarningMsg, N); C.emitReport(std::move(Report)); } @@ -909,7 +864,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C, NonLoc left, NonLoc right) const { // If out-of-bounds checking is turned off, skip the rest. - if (!Filter.CheckCStringOutOfBounds) + if (!OutOfBounds.isEnabled()) return state; // If a previous check has failed, propagate the failure. @@ -1048,7 +1003,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state, // C string. In the context of locations, the only time we can issue such // a warning is for labels. if (std::optional<loc::GotoLabel> Label = Buf.getAs<loc::GotoLabel>()) { - if (Filter.CheckCStringNotNullTerm) { + if (NotNullTerm.isEnabled()) { SmallString<120> buf; llvm::raw_svector_ostream os(buf); assert(CurrentFunctionDescription); @@ -1110,7 +1065,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state, // Other regions (mostly non-data) can't have a reliable C string length. // In this case, an error is emitted and UndefinedVal is returned. // The caller should always be prepared to handle this case. - if (Filter.CheckCStringNotNullTerm) { + if (NotNullTerm.isEnabled()) { SmallString<120> buf; llvm::raw_svector_ostream os(buf); @@ -2873,24 +2828,27 @@ void CStringChecker::checkDeadSymbols(SymbolReaper &SR, } void ento::registerCStringModeling(CheckerManager &Mgr) { - Mgr.registerChecker<CStringChecker>(); + // Other checker relies on the modeling implemented in this checker family, + // so this "modeling checker" can register the 'CStringChecker' backend for + // its callbacks without enabling any of its frontends. + Mgr.getChecker<CStringChecker>(); } -bool ento::shouldRegisterCStringModeling(const CheckerManager &mgr) { +bool ento::shouldRegisterCStringModeling(const CheckerManager &) { return true; } -#define REGISTER_CHECKER(name) \ - void ento::register##name(CheckerManager &mgr) { \ - CStringChecker *checker = mgr.getChecker<CStringChecker>(); \ - checker->Filter.Check##name = true; \ - checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \ +#define REGISTER_CHECKER(NAME) \ + void ento::registerCString##NAME(CheckerManager &Mgr) { \ + Mgr.getChecker<CStringChecker>()->NAME.enable(Mgr); \ } \ \ - bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } + bool ento::shouldRegisterCString##NAME(const CheckerManager &) { \ + return true; \ + } -REGISTER_CHECKER(CStringNullArg) -REGISTER_CHECKER(CStringOutOfBounds) -REGISTER_CHECKER(CStringBufferOverlap) -REGISTER_CHECKER(CStringNotNullTerm) -REGISTER_CHECKER(CStringUninitializedRead) +REGISTER_CHECKER(NullArg) +REGISTER_CHECKER(OutOfBounds) +REGISTER_CHECKER(BufferOverlap) +REGISTER_CHECKER(NotNullTerm) +REGISTER_CHECKER(UninitializedRead) diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp index 839c8bc..a227ca0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp @@ -111,32 +111,12 @@ bool PlacementNewChecker::checkPlaceCapacityIsSufficient( if (!SizeOfPlaceCI) return true; - if ((SizeOfPlaceCI->getValue() < SizeOfTargetCI->getValue()) || - (IsArrayTypeAllocated && - SizeOfPlaceCI->getValue() >= SizeOfTargetCI->getValue())) { + if ((SizeOfPlaceCI->getValue() < SizeOfTargetCI->getValue())) { if (ExplodedNode *N = C.generateErrorNode(C.getState())) { - std::string Msg; - // TODO: use clang constant - if (IsArrayTypeAllocated && - SizeOfPlaceCI->getValue() > SizeOfTargetCI->getValue()) - Msg = std::string(llvm::formatv( - "{0} bytes is possibly not enough for array allocation which " - "requires {1} bytes. Current overhead requires the size of {2} " - "bytes", - SizeOfPlaceCI->getValue(), SizeOfTargetCI->getValue(), - *SizeOfPlaceCI->getValue() - SizeOfTargetCI->getValue())); - else if (IsArrayTypeAllocated && - SizeOfPlaceCI->getValue() == SizeOfTargetCI->getValue()) - Msg = std::string(llvm::formatv( - "Storage provided to placement new is only {0} bytes, " - "whereas the allocated array type requires more space for " - "internal needs", - SizeOfPlaceCI->getValue())); - else - Msg = std::string(llvm::formatv( - "Storage provided to placement new is only {0} bytes, " - "whereas the allocated type requires {1} bytes", - SizeOfPlaceCI->getValue(), SizeOfTargetCI->getValue())); + std::string Msg = + llvm::formatv("Storage provided to placement new is only {0} bytes, " + "whereas the allocated type requires {1} bytes", + SizeOfPlaceCI->getValue(), SizeOfTargetCI->getValue()); auto R = std::make_unique<PathSensitiveBugReport>(SBT, Msg, N); bugreporter::trackExpressionValue(N, NE->getPlacementArg(0), *R); diff --git a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp index 15fd9a0..d2760ca 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp @@ -142,34 +142,19 @@ void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D, //===----------------------------------------------------------------------===// namespace { +class NSOrCFErrorDerefChecker + : public CheckerFamily<check::Location, + check::Event<ImplicitNullDerefEvent>> { + mutable IdentifierInfo *NSErrorII = nullptr; + mutable IdentifierInfo *CFErrorII = nullptr; -class NSErrorDerefBug : public BugType { -public: - NSErrorDerefBug(const CheckerNameRef Checker) - : BugType(Checker, "NSError** null dereference", - "Coding conventions (Apple)") {} -}; - -class CFErrorDerefBug : public BugType { public: - CFErrorDerefBug(const CheckerNameRef Checker) - : BugType(Checker, "CFErrorRef* null dereference", - "Coding conventions (Apple)") {} -}; - -} + CheckerFrontendWithBugType NSError{"NSError** null dereference", + "Coding conventions (Apple)"}; + CheckerFrontendWithBugType CFError{"CFErrorRef* null dereference", + "Coding conventions (Apple)"}; -namespace { -class NSOrCFErrorDerefChecker - : public Checker< check::Location, - check::Event<ImplicitNullDerefEvent> > { - mutable IdentifierInfo *NSErrorII, *CFErrorII; - mutable std::unique_ptr<NSErrorDerefBug> NSBT; - mutable std::unique_ptr<CFErrorDerefBug> CFBT; -public: - bool ShouldCheckNSError = false, ShouldCheckCFError = false; - CheckerNameRef NSErrorName, CFErrorName; - NSOrCFErrorDerefChecker() : NSErrorII(nullptr), CFErrorII(nullptr) {} + StringRef getDebugTag() const override { return "NSOrCFErrorDerefChecker"; } void checkLocation(SVal loc, bool isLoad, const Stmt *S, CheckerContext &C) const; @@ -236,12 +221,12 @@ void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad, if (!CFErrorII) CFErrorII = &Ctx.Idents.get("CFErrorRef"); - if (ShouldCheckNSError && IsNSError(parmT, NSErrorII)) { + if (NSError.isEnabled() && IsNSError(parmT, NSErrorII)) { setFlag<NSErrorOut>(state, state->getSVal(loc.castAs<Loc>()), C); return; } - if (ShouldCheckCFError && IsCFError(parmT, CFErrorII)) { + if (CFError.isEnabled() && IsCFError(parmT, CFErrorII)) { setFlag<CFErrorOut>(state, state->getSVal(loc.castAs<Loc>()), C); return; } @@ -274,19 +259,9 @@ void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const { os << " may be null"; - BugType *bug = nullptr; - if (isNSError) { - if (!NSBT) - NSBT.reset(new NSErrorDerefBug(NSErrorName)); - bug = NSBT.get(); - } - else { - if (!CFBT) - CFBT.reset(new CFErrorDerefBug(CFErrorName)); - bug = CFBT.get(); - } + const BugType &BT = isNSError ? NSError : CFError; BR.emitReport( - std::make_unique<PathSensitiveBugReport>(*bug, os.str(), event.SinkNode)); + std::make_unique<PathSensitiveBugReport>(BT, os.str(), event.SinkNode)); } static bool IsNSError(QualType T, IdentifierInfo *II) { @@ -320,32 +295,21 @@ static bool IsCFError(QualType T, IdentifierInfo *II) { return TT->getDecl()->getIdentifier() == II; } -void ento::registerNSOrCFErrorDerefChecker(CheckerManager &mgr) { - mgr.registerChecker<NSOrCFErrorDerefChecker>(); -} - -bool ento::shouldRegisterNSOrCFErrorDerefChecker(const CheckerManager &mgr) { - return true; -} - -void ento::registerNSErrorChecker(CheckerManager &mgr) { - mgr.registerChecker<NSErrorMethodChecker>(); - NSOrCFErrorDerefChecker *checker = mgr.getChecker<NSOrCFErrorDerefChecker>(); - checker->ShouldCheckNSError = true; - checker->NSErrorName = mgr.getCurrentCheckerName(); -} - -bool ento::shouldRegisterNSErrorChecker(const CheckerManager &mgr) { - return true; -} - -void ento::registerCFErrorChecker(CheckerManager &mgr) { - mgr.registerChecker<CFErrorFunctionChecker>(); - NSOrCFErrorDerefChecker *checker = mgr.getChecker<NSOrCFErrorDerefChecker>(); - checker->ShouldCheckCFError = true; - checker->CFErrorName = mgr.getCurrentCheckerName(); -} +// This source file implements two user-facing checkers ("osx.cocoa.NSError" +// and "osx.coreFoundation.CFError") which are both implemented as the +// combination of two `CheckerFrontend`s that are registered under the same +// name (but otherwise act independently). Among these 2+2 `CheckerFrontend`s +// two are coming from the checker family `NSOrCFErrorDerefChecker` while the +// other two (the `ADDITIONAL_PART`s) are small standalone checkers. +#define REGISTER_CHECKER(NAME, ADDITIONAL_PART) \ + void ento::register##NAME##Checker(CheckerManager &Mgr) { \ + Mgr.getChecker<NSOrCFErrorDerefChecker>()->NAME.enable(Mgr); \ + Mgr.registerChecker<ADDITIONAL_PART>(); \ + } \ + \ + bool ento::shouldRegister##NAME##Checker(const CheckerManager &) { \ + return true; \ + } -bool ento::shouldRegisterCFErrorChecker(const CheckerManager &mgr) { - return true; -} +REGISTER_CHECKER(NSError, NSErrorMethodChecker) +REGISTER_CHECKER(CFError, CFErrorFunctionChecker) diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp index a63497c..019e81f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp @@ -28,23 +28,22 @@ using namespace ento; namespace { class StackAddrEscapeChecker - : public Checker<check::PreCall, check::PreStmt<ReturnStmt>, - check::EndFunction> { + : public CheckerFamily<check::PreCall, check::PreStmt<ReturnStmt>, + check::EndFunction> { mutable IdentifierInfo *dispatch_semaphore_tII = nullptr; - mutable std::unique_ptr<BugType> BT_stackleak; - mutable std::unique_ptr<BugType> BT_returnstack; - mutable std::unique_ptr<BugType> BT_capturedstackasync; - mutable std::unique_ptr<BugType> BT_capturedstackret; public: - enum CheckKind { - CK_StackAddrEscapeChecker, - CK_StackAddrAsyncEscapeChecker, - CK_NumCheckKinds - }; + StringRef getDebugTag() const override { return "StackAddrEscapeChecker"; } + + CheckerFrontend StackAddrEscape; + CheckerFrontend StackAddrAsyncEscape; - bool ChecksEnabled[CK_NumCheckKinds] = {false}; - CheckerNameRef CheckNames[CK_NumCheckKinds]; + const BugType StackLeak{&StackAddrEscape, + "Stack address leaks outside of stack frame"}; + const BugType ReturnStack{&StackAddrEscape, + "Return of address to stack-allocated memory"}; + const BugType CapturedStackAsync{ + &StackAddrAsyncEscape, "Address of stack-allocated memory is captured"}; void checkPreCall(const CallEvent &Call, CheckerContext &C) const; void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; @@ -170,10 +169,6 @@ void StackAddrEscapeChecker::EmitReturnLeakError(CheckerContext &C, ExplodedNode *N = C.generateNonFatalErrorNode(); if (!N) return; - if (!BT_returnstack) - BT_returnstack = std::make_unique<BugType>( - CheckNames[CK_StackAddrEscapeChecker], - "Return of address to stack-allocated memory"); // Generate a report for this bug. SmallString<128> buf; @@ -184,7 +179,7 @@ void StackAddrEscapeChecker::EmitReturnLeakError(CheckerContext &C, EmitReturnedAsPartOfError(os, C.getSVal(RetE), R); auto report = - std::make_unique<PathSensitiveBugReport>(*BT_returnstack, os.str(), N); + std::make_unique<PathSensitiveBugReport>(ReturnStack, os.str(), N); report->addRange(RetE->getSourceRange()); if (range.isValid()) report->addRange(range); @@ -215,16 +210,12 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures( ExplodedNode *N = C.generateNonFatalErrorNode(); if (!N) continue; - if (!BT_capturedstackasync) - BT_capturedstackasync = std::make_unique<BugType>( - CheckNames[CK_StackAddrAsyncEscapeChecker], - "Address of stack-allocated memory is captured"); SmallString<128> Buf; llvm::raw_svector_ostream Out(Buf); SourceRange Range = genName(Out, Region, C.getASTContext()); Out << " is captured by an asynchronously-executed block"; - auto Report = std::make_unique<PathSensitiveBugReport>( - *BT_capturedstackasync, Out.str(), N); + auto Report = std::make_unique<PathSensitiveBugReport>(CapturedStackAsync, + Out.str(), N); if (Range.isValid()) Report->addRange(Range); C.emitReport(std::move(Report)); @@ -233,7 +224,7 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures( void StackAddrEscapeChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { - if (!ChecksEnabled[CK_StackAddrAsyncEscapeChecker]) + if (!StackAddrAsyncEscape.isEnabled()) return; if (!Call.isGlobalCFunction("dispatch_after") && !Call.isGlobalCFunction("dispatch_async")) @@ -357,7 +348,7 @@ FindEscapingStackRegions(CheckerContext &C, const Expr *RetE, SVal RetVal) { void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const { - if (!ChecksEnabled[CK_StackAddrEscapeChecker]) + if (!StackAddrEscape.isEnabled()) return; const Expr *RetE = RS->getRetValue(); @@ -456,7 +447,7 @@ static bool isInvalidatedSymbolRegion(const MemRegion *Region) { void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS, CheckerContext &Ctx) const { - if (!ChecksEnabled[CK_StackAddrEscapeChecker]) + if (!StackAddrEscape.isEnabled()) return; ExplodedNode *Node = Ctx.getPredecessor(); @@ -581,11 +572,6 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS, if (!N) return; - if (!BT_stackleak) - BT_stackleak = - std::make_unique<BugType>(CheckNames[CK_StackAddrEscapeChecker], - "Stack address leaks outside of stack frame"); - for (const auto &P : Cb.V) { const MemRegion *Referrer = P.first->getBaseRegion(); const MemRegion *Referred = P.second; @@ -604,7 +590,7 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS, Out << " is still referred to by a temporary object on the stack" << CommonSuffix; auto Report = - std::make_unique<PathSensitiveBugReport>(*BT_stackleak, Out.str(), N); + std::make_unique<PathSensitiveBugReport>(StackLeak, Out.str(), N); if (Range.isValid()) Report->addRange(Range); Ctx.emitReport(std::move(Report)); @@ -618,7 +604,7 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS, Out << " is still referred to by the " << *ReferrerVariable << CommonSuffix; auto Report = - std::make_unique<PathSensitiveBugReport>(*BT_stackleak, Out.str(), N); + std::make_unique<PathSensitiveBugReport>(StackLeak, Out.str(), N); if (Range.isValid()) Report->addRange(Range); @@ -626,23 +612,14 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS, } } -void ento::registerStackAddrEscapeBase(CheckerManager &mgr) { - mgr.registerChecker<StackAddrEscapeChecker>(); -} - -bool ento::shouldRegisterStackAddrEscapeBase(const CheckerManager &mgr) { - return true; -} - -#define REGISTER_CHECKER(name) \ - void ento::register##name(CheckerManager &Mgr) { \ - StackAddrEscapeChecker *Chk = Mgr.getChecker<StackAddrEscapeChecker>(); \ - Chk->ChecksEnabled[StackAddrEscapeChecker::CK_##name] = true; \ - Chk->CheckNames[StackAddrEscapeChecker::CK_##name] = \ - Mgr.getCurrentCheckerName(); \ +#define REGISTER_CHECKER(NAME) \ + void ento::register##NAME##Checker(CheckerManager &Mgr) { \ + Mgr.getChecker<StackAddrEscapeChecker>()->NAME.enable(Mgr); \ } \ \ - bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } + bool ento::shouldRegister##NAME##Checker(const CheckerManager &) { \ + return true; \ + } -REGISTER_CHECKER(StackAddrEscapeChecker) -REGISTER_CHECKER(StackAddrAsyncEscapeChecker) +REGISTER_CHECKER(StackAddrEscape) +REGISTER_CHECKER(StackAddrAsyncEscape) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index f1a25a7..4ddf8fd 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -868,7 +868,8 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, QualType T = Ex->getTypeOfArgument(); for (ExplodedNode *N : CheckedSet) { - if (Ex->getKind() == UETT_SizeOf) { + if (Ex->getKind() == UETT_SizeOf || Ex->getKind() == UETT_DataSizeOf || + Ex->getKind() == UETT_CountOf) { if (!T->isIncompleteType() && !T->isConstantSizeType()) { assert(T->isVariableArrayType() && "Unknown non-constant-sized type."); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 8535384..fe70558 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -1227,7 +1227,7 @@ void ExprEngine::VisitAttributedStmt(const AttributedStmt *A, for (const auto *Attr : getSpecificAttrs<CXXAssumeAttr>(A->getAttrs())) { for (ExplodedNode *N : CheckerPreStmt) { - Visit(Attr->getAssumption(), N, EvalSet); + Visit(Attr->getAssumption()->IgnoreParens(), N, EvalSet); } } diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp index 3e68373..0058a0d 100644 --- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -1219,6 +1219,16 @@ MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx, const ASTContext &Ctx) { QualType T = Ctx.getCanonicalType(elementType).getUnqualifiedType(); + // The address space must be preserved because some target-specific address + // spaces influence the size of the pointer value which is represented by the + // element region. + LangAS AS = elementType.getAddressSpace(); + if (AS != LangAS::Default) { + Qualifiers Quals; + Quals.setAddressSpace(AS); + T = Ctx.getQualifiedType(T, Quals); + } + llvm::FoldingSetNodeID ID; ElementRegion::ProfileRegion(ID, T, Idx, superRegion); diff --git a/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp b/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp index 5d392af..7bc34f6 100644 --- a/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp @@ -43,8 +43,8 @@ void ModelInjector::onBodySynthesis(const NamedDecl *D) { if (Bodies.count(D->getName()) != 0) return; - SourceManager &SM = CI.getSourceManager(); - FileID mainFileID = SM.getMainFileID(); + llvm::IntrusiveRefCntPtr<SourceManager> SM = CI.getSourceManagerPtr(); + FileID mainFileID = SM->getMainFileID(); llvm::StringRef modelPath = CI.getAnalyzerOpts().ModelPath; @@ -80,14 +80,14 @@ void ModelInjector::onBodySynthesis(const NamedDecl *D) { new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()), /*ShouldOwnClient=*/true); - Instance.getDiagnostics().setSourceManager(&SM); + Instance.getDiagnostics().setSourceManager(SM.get()); // The instance wants to take ownership, however DisableFree frontend option // is set to true to avoid double free issues - Instance.setFileManager(&CI.getFileManager()); - Instance.setSourceManager(&SM); + Instance.setFileManager(CI.getFileManagerPtr()); + Instance.setSourceManager(SM); Instance.setPreprocessor(CI.getPreprocessorPtr()); - Instance.setASTContext(&CI.getASTContext()); + Instance.setASTContext(CI.getASTContextPtr()); Instance.getPreprocessor().InitializeForModelFile(); @@ -108,5 +108,5 @@ void ModelInjector::onBodySynthesis(const NamedDecl *D) { // the main file id is changed to the model file during parsing and it needs // to be reset to the former main file id after parsing of the model file // is done. - SM.setMainFileID(mainFileID); + SM->setMainFileID(mainFileID); } diff --git a/clang/lib/Tooling/CompilationDatabase.cpp b/clang/lib/Tooling/CompilationDatabase.cpp index d5fc216..860457a 100644 --- a/clang/lib/Tooling/CompilationDatabase.cpp +++ b/clang/lib/Tooling/CompilationDatabase.cpp @@ -241,9 +241,8 @@ static bool stripPositionalArgs(std::vector<const char *> Args, llvm::raw_string_ostream Output(ErrorMsg); TextDiagnosticPrinter DiagnosticPrinter(Output, DiagOpts); UnusedInputDiagConsumer DiagClient(DiagnosticPrinter); - DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts, - &DiagClient, false); + DiagnosticsEngine Diagnostics(DiagnosticIDs::create(), DiagOpts, &DiagClient, + false); // The clang executable path isn't required since the jobs the driver builds // will not be executed. diff --git a/clang/lib/Tooling/Core/Replacement.cpp b/clang/lib/Tooling/Core/Replacement.cpp index 1506218..10bdc22 100644 --- a/clang/lib/Tooling/Core/Replacement.cpp +++ b/clang/lib/Tooling/Core/Replacement.cpp @@ -581,12 +581,11 @@ llvm::Expected<std::string> applyAllReplacements(StringRef Code, if (Replaces.empty()) return Code.str(); - IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( - new llvm::vfs::InMemoryFileSystem); + auto InMemoryFileSystem = + llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); FileManager Files(FileSystemOptions(), InMemoryFileSystem); DiagnosticOptions DiagOpts; - DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts); + DiagnosticsEngine Diagnostics(DiagnosticIDs::create(), DiagOpts); SourceManager SourceMgr(Diagnostics, Files); Rewriter Rewrite(SourceMgr, LangOptions()); InMemoryFileSystem->addFile( diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 8ce2706..b2b61de7 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -605,8 +605,8 @@ DependencyScanningWorker::DependencyScanningWorker( switch (Service.getMode()) { case ScanningMode::DependencyDirectivesScan: - DepFS = - new DependencyScanningWorkerFilesystem(Service.getSharedCache(), FS); + DepFS = llvm::makeIntrusiveRefCnt<DependencyScanningWorkerFilesystem>( + Service.getSharedCache(), FS); BaseFS = DepFS; break; case ScanningMode::CanonicalPreprocessing: diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp index 37f8b94..d67178c 100644 --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -144,30 +144,8 @@ static void optimizeDiagnosticOpts(DiagnosticOptions &Opts, static void optimizeCWD(CowCompilerInvocation &BuildInvocation, StringRef CWD) { BuildInvocation.getMutFileSystemOpts().WorkingDir.clear(); - if (BuildInvocation.getCodeGenOpts().DwarfVersion) { - // It is necessary to explicitly set the DebugCompilationDir - // to a common directory (e.g. root) if IgnoreCWD is true. - // When IgnoreCWD is true, the module's content should not - // depend on the current working directory. However, if dwarf - // information is needed (when CGOpts.DwarfVersion is - // non-zero), then CGOpts.DebugCompilationDir must be - // populated, because otherwise the current working directory - // will be automatically embedded in the dwarf information in - // the pcm, contradicting the assumption that it is safe to - // ignore the CWD. Thus in such cases, - // CGOpts.DebugCompilationDir is explicitly set to a common - // directory. - // FIXME: It is still excessive to create a copy of - // CodeGenOpts for each module. Since we do not modify the - // CodeGenOpts otherwise per module, the following code - // ends up generating identical CodeGenOpts for each module - // with DebugCompilationDir pointing to the root directory. - // We can optimize this away by creating a _single_ copy of - // CodeGenOpts whose DebugCompilationDir points to the root - // directory and reuse it across modules. - BuildInvocation.getMutCodeGenOpts().DebugCompilationDir = - llvm::sys::path::root_path(CWD); - } + BuildInvocation.getMutCodeGenOpts().DebugCompilationDir.clear(); + BuildInvocation.getMutCodeGenOpts().CoverageCompilationDir.clear(); } static std::vector<std::string> splitString(std::string S, char Separator) { diff --git a/clang/lib/Tooling/Refactoring.cpp b/clang/lib/Tooling/Refactoring.cpp index d2b0b37..9b1af237 100644 --- a/clang/lib/Tooling/Refactoring.cpp +++ b/clang/lib/Tooling/Refactoring.cpp @@ -39,9 +39,8 @@ int RefactoringTool::runAndSave(FrontendActionFactory *ActionFactory) { LangOptions DefaultLangOptions; DiagnosticOptions DiagOpts; TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), DiagOpts); - DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts, - &DiagnosticPrinter, false); + DiagnosticsEngine Diagnostics(DiagnosticIDs::create(), DiagOpts, + &DiagnosticPrinter, false); SourceManager Sources(Diagnostics, getFiles()); Rewriter Rewrite(Sources, DefaultLangOptions); diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp index 5333956..45dfdf4 100644 --- a/clang/lib/Tooling/Tooling.cpp +++ b/clang/lib/Tooling/Tooling.cpp @@ -212,8 +212,8 @@ bool runToolOnCodeWithArgs( SmallString<16> FileNameStorage; StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage); - llvm::IntrusiveRefCntPtr<FileManager> Files( - new FileManager(FileSystemOptions(), VFS)); + llvm::IntrusiveRefCntPtr<FileManager> Files = + llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions(), VFS); ArgumentsAdjuster Adjuster = getClangStripDependencyFileAdjuster(); ToolInvocation Invocation( getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileNameRef), FileNameRef), @@ -227,10 +227,11 @@ bool runToolOnCodeWithArgs( const Twine &ToolName, std::shared_ptr<PCHContainerOperations> PCHContainerOps, const FileContentMappings &VirtualMappedFiles) { - llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem( - new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())); - llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( - new llvm::vfs::InMemoryFileSystem); + auto OverlayFileSystem = + llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>( + llvm::vfs::getRealFileSystem()); + auto InMemoryFileSystem = + llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); OverlayFileSystem->pushOverlay(InMemoryFileSystem); SmallString<1024> CodeStorage; @@ -403,7 +404,7 @@ bool ToolInvocation::run() { } const std::unique_ptr<driver::Driver> Driver( - newDriver(&*Diagnostics, BinaryName, &Files->getVirtualFileSystem())); + newDriver(&*Diagnostics, BinaryName, Files->getVirtualFileSystemPtr())); // The "input file not found" diagnostics from the driver are useful. // The driver is only aware of the VFS working directory, but some clients // change this at the FileManager level instead. @@ -473,10 +474,13 @@ ClangTool::ClangTool(const CompilationDatabase &Compilations, IntrusiveRefCntPtr<FileManager> Files) : Compilations(Compilations), SourcePaths(SourcePaths), PCHContainerOps(std::move(PCHContainerOps)), - OverlayFileSystem(new llvm::vfs::OverlayFileSystem(std::move(BaseFS))), - InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem), + OverlayFileSystem(llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>( + std::move(BaseFS))), + InMemoryFileSystem( + llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>()), Files(Files ? Files - : new FileManager(FileSystemOptions(), OverlayFileSystem)) { + : llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions(), + OverlayFileSystem)) { OverlayFileSystem->pushOverlay(InMemoryFileSystem); appendArgumentsAdjuster(getClangStripOutputAdjuster()); appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster()); @@ -692,13 +696,15 @@ std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs( IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS) { std::vector<std::unique_ptr<ASTUnit>> ASTs; ASTBuilderAction Action(ASTs); - llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem( - new llvm::vfs::OverlayFileSystem(std::move(BaseFS))); - llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( - new llvm::vfs::InMemoryFileSystem); + auto OverlayFileSystem = + llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>( + std::move(BaseFS)); + auto InMemoryFileSystem = + llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); OverlayFileSystem->pushOverlay(InMemoryFileSystem); - llvm::IntrusiveRefCntPtr<FileManager> Files( - new FileManager(FileSystemOptions(), OverlayFileSystem)); + llvm::IntrusiveRefCntPtr<FileManager> Files = + llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions(), + OverlayFileSystem); ToolInvocation Invocation( getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileName), FileName), |