diff options
Diffstat (limited to 'clang/lib')
72 files changed, 1962 insertions, 730 deletions
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 84f7e62..20836f6 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -2508,7 +2508,7 @@ bool Compiler<Emitter>::VisitAbstractConditionalOperator( }; if (std::optional<bool> BoolValue = getBoolValue(Condition)) { - if (BoolValue) + if (*BoolValue) return visitChildExpr(TrueExpr); return visitChildExpr(FalseExpr); } @@ -3235,7 +3235,8 @@ bool Compiler<Emitter>::VisitCXXConstructExpr(const CXXConstructExpr *E) { return this->visitInitializer(E->getArg(0)); // Zero initialization. - if (E->requiresZeroInitialization()) { + bool ZeroInit = E->requiresZeroInitialization(); + if (ZeroInit) { const Record *R = getRecord(E->getType()); if (!this->visitZeroRecordInitializer(R, E)) @@ -3246,6 +3247,19 @@ bool Compiler<Emitter>::VisitCXXConstructExpr(const CXXConstructExpr *E) { return true; } + // Avoid materializing a temporary for an elidable copy/move constructor. + if (!ZeroInit && E->isElidable()) { + const Expr *SrcObj = E->getArg(0); + assert(SrcObj->isTemporaryObject(Ctx.getASTContext(), Ctor->getParent())); + assert(Ctx.getASTContext().hasSameUnqualifiedType(E->getType(), + SrcObj->getType())); + if (const auto *ME = dyn_cast<MaterializeTemporaryExpr>(SrcObj)) { + if (!this->emitCheckFunctionDecl(Ctor, E)) + return false; + return this->visitInitializer(ME->getSubExpr()); + } + } + const Function *Func = getFunction(Ctor); if (!Func) @@ -4175,7 +4189,7 @@ bool Compiler<Emitter>::VisitStmtExpr(const StmtExpr *E) { StmtExprScope<Emitter> SS(this); const CompoundStmt *CS = E->getSubStmt(); - const Stmt *Result = CS->getStmtExprResult(); + const Stmt *Result = CS->body_back(); for (const Stmt *S : CS->body()) { if (S != Result) { if (!this->visitStmt(S)) diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index a2fb0fb..1f2ae92 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -919,33 +919,8 @@ bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { return true; } -static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { - - if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) { - const SourceLocation &Loc = S.Current->getLocation(OpPC); - S.CCEDiag(Loc, diag::note_constexpr_virtual_call); - return false; - } - - if (S.checkingPotentialConstantExpression() && S.Current->getDepth() != 0) - return false; - - if (F->isValid() && F->hasBody() && F->isConstexpr()) - return true; - - const FunctionDecl *DiagDecl = F->getDecl(); - const FunctionDecl *Definition = nullptr; - DiagDecl->getBody(Definition); - - if (!Definition && S.checkingPotentialConstantExpression() && - DiagDecl->isConstexpr()) { - return false; - } - - // Implicitly constexpr. - if (F->isLambdaStaticInvoker()) - return true; - +static bool diagnoseCallableDecl(InterpState &S, CodePtr OpPC, + const FunctionDecl *DiagDecl) { // Bail out if the function declaration itself is invalid. We will // have produced a relevant diagnostic while parsing it, so just // note the problematic sub-expression. @@ -953,11 +928,10 @@ static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { return Invalid(S, OpPC); // Diagnose failed assertions specially. - if (S.Current->getLocation(OpPC).isMacroID() && - F->getDecl()->getIdentifier()) { + if (S.Current->getLocation(OpPC).isMacroID() && DiagDecl->getIdentifier()) { // FIXME: Instead of checking for an implementation-defined function, // check and evaluate the assert() macro. - StringRef Name = F->getDecl()->getName(); + StringRef Name = DiagDecl->getName(); bool AssertFailed = Name == "__assert_rtn" || Name == "__assert_fail" || Name == "_wassert"; if (AssertFailed) { @@ -1004,7 +978,7 @@ static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { // for a constant expression. It might be defined at the point we're // actually calling it. bool IsExtern = DiagDecl->getStorageClass() == SC_Extern; - bool IsDefined = F->isDefined(); + bool IsDefined = DiagDecl->isDefined(); if (!IsDefined && !IsExtern && DiagDecl->isConstexpr() && S.checkingPotentialConstantExpression()) return false; @@ -1027,6 +1001,35 @@ static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { return false; } +static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { + if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) { + const SourceLocation &Loc = S.Current->getLocation(OpPC); + S.CCEDiag(Loc, diag::note_constexpr_virtual_call); + return false; + } + + if (S.checkingPotentialConstantExpression() && S.Current->getDepth() != 0) + return false; + + if (F->isValid() && F->hasBody() && F->isConstexpr()) + return true; + + const FunctionDecl *DiagDecl = F->getDecl(); + const FunctionDecl *Definition = nullptr; + DiagDecl->getBody(Definition); + + if (!Definition && S.checkingPotentialConstantExpression() && + DiagDecl->isConstexpr()) { + return false; + } + + // Implicitly constexpr. + if (F->isLambdaStaticInvoker()) + return true; + + return diagnoseCallableDecl(S, OpPC, DiagDecl); +} + static bool CheckCallDepth(InterpState &S, CodePtr OpPC) { if ((S.Current->getDepth() + 1) > S.getLangOpts().ConstexprCallDepth) { S.FFDiag(S.Current->getSource(OpPC), @@ -1500,6 +1503,21 @@ bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { return CheckActive(S, OpPC, Ptr, AK_Destroy); } +/// Opcode. Check if the function decl can be called at compile time. +bool CheckFunctionDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *FD) { + if (S.checkingPotentialConstantExpression() && S.Current->getDepth() != 0) + return false; + + const FunctionDecl *Definition = nullptr; + const Stmt *Body = FD->getBody(Definition); + + if (Definition && Body && + (Definition->isConstexpr() || Definition->hasAttr<MSConstexprAttr>())) + return true; + + return diagnoseCallableDecl(S, OpPC, FD); +} + static void compileFunction(InterpState &S, const Function *Func) { const FunctionDecl *Definition = Func->getDecl()->getDefinition(); if (!Definition) diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 6877b03..c16408c 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -117,6 +117,7 @@ bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits, bool TargetIsUCharOrByte); bool CheckBCPResult(InterpState &S, const Pointer &Ptr); bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr); +bool CheckFunctionDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *FD); bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC, const FixedPoint &FP); diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 9991e36..0ef130c 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -3831,6 +3831,42 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, return Result; }); + case clang::X86::BI__builtin_ia32_ktestcqi: + case clang::X86::BI__builtin_ia32_ktestchi: + case clang::X86::BI__builtin_ia32_ktestcsi: + case clang::X86::BI__builtin_ia32_ktestcdi: + return interp__builtin_elementwise_int_binop( + S, OpPC, Call, [](const APSInt &A, const APSInt &B) { + return APInt(sizeof(unsigned char) * 8, (~A & B) == 0); + }); + + case clang::X86::BI__builtin_ia32_ktestzqi: + case clang::X86::BI__builtin_ia32_ktestzhi: + case clang::X86::BI__builtin_ia32_ktestzsi: + case clang::X86::BI__builtin_ia32_ktestzdi: + return interp__builtin_elementwise_int_binop( + S, OpPC, Call, [](const APSInt &A, const APSInt &B) { + return APInt(sizeof(unsigned char) * 8, (A & B) == 0); + }); + + case clang::X86::BI__builtin_ia32_kortestcqi: + case clang::X86::BI__builtin_ia32_kortestchi: + case clang::X86::BI__builtin_ia32_kortestcsi: + case clang::X86::BI__builtin_ia32_kortestcdi: + return interp__builtin_elementwise_int_binop( + S, OpPC, Call, [](const APSInt &A, const APSInt &B) { + return APInt(sizeof(unsigned char) * 8, ~(A | B) == 0); + }); + + case clang::X86::BI__builtin_ia32_kortestzqi: + case clang::X86::BI__builtin_ia32_kortestzhi: + case clang::X86::BI__builtin_ia32_kortestzsi: + case clang::X86::BI__builtin_ia32_kortestzdi: + return interp__builtin_elementwise_int_binop( + S, OpPC, Call, [](const APSInt &A, const APSInt &B) { + return APInt(sizeof(unsigned char) * 8, (A | B) == 0); + }); + case clang::X86::BI__builtin_ia32_lzcnt_u16: case clang::X86::BI__builtin_ia32_lzcnt_u32: case clang::X86::BI__builtin_ia32_lzcnt_u64: diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index 1c17ad9e..a2eaa61 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -53,6 +53,7 @@ def ArgBool : ArgType { let Name = "bool"; } def ArgFixedPoint : ArgType { let Name = "FixedPoint"; let AsRef = true; } def ArgFunction : ArgType { let Name = "const Function *"; } +def ArgFunctionDecl : ArgType { let Name = "const FunctionDecl *"; } def ArgRecordDecl : ArgType { let Name = "const RecordDecl *"; } def ArgRecordField : ArgType { let Name = "const Record::Field *"; } def ArgFltSemantics : ArgType { let Name = "const llvm::fltSemantics *"; } @@ -422,6 +423,8 @@ def CheckLiteralType : Opcode { def CheckArraySize : Opcode { let Args = [ArgUint64]; } +def CheckFunctionDecl : Opcode { let Args = [ArgFunctionDecl]; } + // [] -> [Value] def GetGlobal : AccessOpcode; def GetGlobalUnchecked : AccessOpcode; diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index 4d34e0b..c468303 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -197,7 +197,8 @@ UnsignedOrNone Program::createGlobal(const ValueDecl *VD, const Expr *Init) { // global variable and points to the block we just created. if (auto DummyIt = DummyVariables.find(Redecl); DummyIt != DummyVariables.end()) { - assert(!Globals[DummyIt->second]->block()->hasPointers()); + Global *Dummy = Globals[DummyIt->second]; + Dummy->block()->movePointersTo(NewGlobal->block()); Globals[DummyIt->second] = NewGlobal; DummyVariables.erase(DummyIt); } diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index e0cf0de..638080e 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -178,7 +178,7 @@ ExprDependence clang::computeDependence(StmtExpr *E, unsigned TemplateDepth) { auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); // Propagate dependence of the result. if (const auto *CompoundExprResult = - dyn_cast_or_null<ValueStmt>(E->getSubStmt()->getStmtExprResult())) + dyn_cast_or_null<ValueStmt>(E->getSubStmt()->body_back())) if (const Expr *ResultExpr = CompoundExprResult->getExprStmt()) D |= ResultExpr->getDependence(); // Note: we treat a statement-expression in a dependent context as always diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 193f87c..972d9fe 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -3829,6 +3829,351 @@ static bool CheckArraySize(EvalInfo &Info, const ConstantArrayType *CAT, /*Diag=*/true); } +static bool handleScalarCast(EvalInfo &Info, const FPOptions FPO, const Expr *E, + QualType SourceTy, QualType DestTy, + APValue const &Original, APValue &Result) { + // boolean must be checked before integer + // since IsIntegerType() is true for bool + if (SourceTy->isBooleanType()) { + if (DestTy->isBooleanType()) { + Result = Original; + return true; + } + if (DestTy->isIntegerType() || DestTy->isRealFloatingType()) { + bool BoolResult; + if (!HandleConversionToBool(Original, BoolResult)) + return false; + uint64_t IntResult = BoolResult; + QualType IntType = DestTy->isIntegerType() + ? DestTy + : Info.Ctx.getIntTypeForBitwidth(64, false); + Result = APValue(Info.Ctx.MakeIntValue(IntResult, IntType)); + } + if (DestTy->isRealFloatingType()) { + APValue Result2 = APValue(APFloat(0.0)); + if (!HandleIntToFloatCast(Info, E, FPO, + Info.Ctx.getIntTypeForBitwidth(64, false), + Result.getInt(), DestTy, Result2.getFloat())) + return false; + Result = Result2; + } + return true; + } + if (SourceTy->isIntegerType()) { + if (DestTy->isRealFloatingType()) { + Result = APValue(APFloat(0.0)); + return HandleIntToFloatCast(Info, E, FPO, SourceTy, Original.getInt(), + DestTy, Result.getFloat()); + } + if (DestTy->isBooleanType()) { + bool BoolResult; + if (!HandleConversionToBool(Original, BoolResult)) + return false; + uint64_t IntResult = BoolResult; + Result = APValue(Info.Ctx.MakeIntValue(IntResult, DestTy)); + return true; + } + if (DestTy->isIntegerType()) { + Result = APValue( + HandleIntToIntCast(Info, E, DestTy, SourceTy, Original.getInt())); + return true; + } + } else if (SourceTy->isRealFloatingType()) { + if (DestTy->isRealFloatingType()) { + Result = Original; + return HandleFloatToFloatCast(Info, E, SourceTy, DestTy, + Result.getFloat()); + } + if (DestTy->isBooleanType()) { + bool BoolResult; + if (!HandleConversionToBool(Original, BoolResult)) + return false; + uint64_t IntResult = BoolResult; + Result = APValue(Info.Ctx.MakeIntValue(IntResult, DestTy)); + return true; + } + if (DestTy->isIntegerType()) { + Result = APValue(APSInt()); + return HandleFloatToIntCast(Info, E, SourceTy, Original.getFloat(), + DestTy, Result.getInt()); + } + } + + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); + return false; +} + +// do the heavy lifting for casting to aggregate types +// because we have to deal with bitfields specially +static bool constructAggregate(EvalInfo &Info, const FPOptions FPO, + const Expr *E, APValue &Result, + QualType ResultType, + SmallVectorImpl<APValue> &Elements, + SmallVectorImpl<QualType> &ElTypes) { + + SmallVector<std::tuple<APValue *, QualType, unsigned>> WorkList = { + {&Result, ResultType, 0}}; + + unsigned ElI = 0; + while (!WorkList.empty() && ElI < Elements.size()) { + auto [Res, Type, BitWidth] = WorkList.pop_back_val(); + + if (Type->isRealFloatingType()) { + if (!handleScalarCast(Info, FPO, E, ElTypes[ElI], Type, Elements[ElI], + *Res)) + return false; + ElI++; + continue; + } + if (Type->isIntegerType()) { + if (!handleScalarCast(Info, FPO, E, ElTypes[ElI], Type, Elements[ElI], + *Res)) + return false; + if (BitWidth > 0) { + if (!Res->isInt()) + return false; + APSInt &Int = Res->getInt(); + unsigned OldBitWidth = Int.getBitWidth(); + unsigned NewBitWidth = BitWidth; + if (NewBitWidth < OldBitWidth) + Int = Int.trunc(NewBitWidth).extend(OldBitWidth); + } + ElI++; + continue; + } + if (Type->isVectorType()) { + QualType ElTy = Type->castAs<VectorType>()->getElementType(); + unsigned NumEl = Type->castAs<VectorType>()->getNumElements(); + SmallVector<APValue> Vals(NumEl); + for (unsigned I = 0; I < NumEl; ++I) { + if (!handleScalarCast(Info, FPO, E, ElTypes[ElI], ElTy, Elements[ElI], + Vals[I])) + return false; + ElI++; + } + *Res = APValue(Vals.data(), NumEl); + continue; + } + if (Type->isConstantArrayType()) { + QualType ElTy = cast<ConstantArrayType>(Info.Ctx.getAsArrayType(Type)) + ->getElementType(); + uint64_t Size = + cast<ConstantArrayType>(Info.Ctx.getAsArrayType(Type))->getZExtSize(); + *Res = APValue(APValue::UninitArray(), Size, Size); + for (int64_t I = Size - 1; I > -1; --I) + WorkList.emplace_back(&Res->getArrayInitializedElt(I), ElTy, 0u); + continue; + } + if (Type->isRecordType()) { + const RecordDecl *RD = Type->getAsRecordDecl(); + + unsigned NumBases = 0; + if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) + NumBases = CXXRD->getNumBases(); + + *Res = APValue(APValue::UninitStruct(), NumBases, + std::distance(RD->field_begin(), RD->field_end())); + + SmallVector<std::tuple<APValue *, QualType, unsigned>> ReverseList; + // we need to traverse backwards + // Visit the base classes. + if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { + if (CXXRD->getNumBases() > 0) { + assert(CXXRD->getNumBases() == 1); + const CXXBaseSpecifier &BS = CXXRD->bases_begin()[0]; + ReverseList.emplace_back(&Res->getStructBase(0), BS.getType(), 0u); + } + } + + // Visit the fields. + for (FieldDecl *FD : RD->fields()) { + unsigned FDBW = 0; + if (FD->isUnnamedBitField()) + continue; + if (FD->isBitField()) { + FDBW = FD->getBitWidthValue(); + } + + ReverseList.emplace_back(&Res->getStructField(FD->getFieldIndex()), + FD->getType(), FDBW); + } + + std::reverse(ReverseList.begin(), ReverseList.end()); + llvm::append_range(WorkList, ReverseList); + continue; + } + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); + return false; + } + return true; +} + +static bool handleElementwiseCast(EvalInfo &Info, const Expr *E, + const FPOptions FPO, + SmallVectorImpl<APValue> &Elements, + SmallVectorImpl<QualType> &SrcTypes, + SmallVectorImpl<QualType> &DestTypes, + SmallVectorImpl<APValue> &Results) { + + assert((Elements.size() == SrcTypes.size()) && + (Elements.size() == DestTypes.size())); + + for (unsigned I = 0, ESz = Elements.size(); I < ESz; ++I) { + APValue Original = Elements[I]; + QualType SourceTy = SrcTypes[I]; + QualType DestTy = DestTypes[I]; + + if (!handleScalarCast(Info, FPO, E, SourceTy, DestTy, Original, Results[I])) + return false; + } + return true; +} + +static unsigned elementwiseSize(EvalInfo &Info, QualType BaseTy) { + + SmallVector<QualType> WorkList = {BaseTy}; + + unsigned Size = 0; + while (!WorkList.empty()) { + QualType Type = WorkList.pop_back_val(); + if (Type->isRealFloatingType() || Type->isIntegerType() || + Type->isBooleanType()) { + ++Size; + continue; + } + if (Type->isVectorType()) { + unsigned NumEl = Type->castAs<VectorType>()->getNumElements(); + Size += NumEl; + continue; + } + if (Type->isConstantArrayType()) { + QualType ElTy = cast<ConstantArrayType>(Info.Ctx.getAsArrayType(Type)) + ->getElementType(); + uint64_t ArrSize = + cast<ConstantArrayType>(Info.Ctx.getAsArrayType(Type))->getZExtSize(); + for (uint64_t I = 0; I < ArrSize; ++I) { + WorkList.push_back(ElTy); + } + continue; + } + if (Type->isRecordType()) { + const RecordDecl *RD = Type->getAsRecordDecl(); + + // Visit the base classes. + if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { + if (CXXRD->getNumBases() > 0) { + assert(CXXRD->getNumBases() == 1); + const CXXBaseSpecifier &BS = CXXRD->bases_begin()[0]; + WorkList.push_back(BS.getType()); + } + } + + // visit the fields. + for (FieldDecl *FD : RD->fields()) { + if (FD->isUnnamedBitField()) + continue; + WorkList.push_back(FD->getType()); + } + continue; + } + } + return Size; +} + +static bool hlslAggSplatHelper(EvalInfo &Info, const Expr *E, APValue &SrcVal, + QualType &SrcTy) { + SrcTy = E->getType(); + + if (!Evaluate(SrcVal, Info, E)) + return false; + + assert(SrcVal.isFloat() || SrcVal.isInt() || + (SrcVal.isVector() && SrcVal.getVectorLength() == 1) && + "Not a valid HLSLAggregateSplatCast."); + + if (SrcVal.isVector()) { + assert(SrcTy->isVectorType() && "Type mismatch."); + SrcTy = SrcTy->castAs<VectorType>()->getElementType(); + SrcVal = SrcVal.getVectorElt(0); + } + return true; +} + +static bool flattenAPValue(EvalInfo &Info, const Expr *E, APValue Value, + QualType BaseTy, SmallVectorImpl<APValue> &Elements, + SmallVectorImpl<QualType> &Types, unsigned Size) { + + SmallVector<std::pair<APValue, QualType>> WorkList = {{Value, BaseTy}}; + unsigned Populated = 0; + while (!WorkList.empty() && Populated < Size) { + auto [Work, Type] = WorkList.pop_back_val(); + + if (Work.isFloat() || Work.isInt()) { + Elements.push_back(Work); + Types.push_back(Type); + Populated++; + continue; + } + if (Work.isVector()) { + assert(Type->isVectorType() && "Type mismatch."); + QualType ElTy = Type->castAs<VectorType>()->getElementType(); + for (unsigned I = 0; I < Work.getVectorLength() && Populated < Size; + I++) { + Elements.push_back(Work.getVectorElt(I)); + Types.push_back(ElTy); + Populated++; + } + continue; + } + if (Work.isArray()) { + assert(Type->isConstantArrayType() && "Type mismatch."); + QualType ElTy = cast<ConstantArrayType>(Info.Ctx.getAsArrayType(Type)) + ->getElementType(); + for (int64_t I = Work.getArraySize() - 1; I > -1; --I) { + WorkList.emplace_back(Work.getArrayInitializedElt(I), ElTy); + } + continue; + } + + if (Work.isStruct()) { + assert(Type->isRecordType() && "Type mismatch."); + + const RecordDecl *RD = Type->getAsRecordDecl(); + + SmallVector<std::pair<APValue, QualType>> ReverseList; + // Visit the fields. + for (FieldDecl *FD : RD->fields()) { + if (FD->isUnnamedBitField()) + continue; + ReverseList.emplace_back(Work.getStructField(FD->getFieldIndex()), + FD->getType()); + } + + std::reverse(ReverseList.begin(), ReverseList.end()); + llvm::append_range(WorkList, ReverseList); + + // Visit the base classes. + if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { + if (CXXRD->getNumBases() > 0) { + assert(CXXRD->getNumBases() == 1); + const CXXBaseSpecifier &BS = CXXRD->bases_begin()[0]; + const APValue &Base = Work.getStructBase(0); + + // Can happen in error cases. + if (!Base.isStruct()) + return false; + + WorkList.emplace_back(Base, BS.getType()); + } + } + continue; + } + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); + return false; + } + return true; +} + namespace { /// A handle to a complete object (an object that is not a subobject of /// another object). @@ -4639,6 +4984,30 @@ handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, QualType Type, return Obj && extractSubobject(Info, Conv, Obj, LVal.Designator, RVal, AK); } +static bool hlslElementwiseCastHelper(EvalInfo &Info, const Expr *E, + QualType DestTy, + SmallVectorImpl<APValue> &SrcVals, + SmallVectorImpl<QualType> &SrcTypes) { + APValue Val; + if (!Evaluate(Val, Info, E)) + return false; + + // must be dealing with a record + if (Val.isLValue()) { + LValue LVal; + LVal.setFrom(Info.Ctx, Val); + if (!handleLValueToRValueConversion(Info, E, E->getType(), LVal, Val)) + return false; + } + + unsigned NEls = elementwiseSize(Info, DestTy); + // flatten the source + if (!flattenAPValue(Info, E, Val, E->getType(), SrcVals, SrcTypes, NEls)) + return false; + + return true; +} + /// Perform an assignment of Val to LVal. Takes ownership of Val. static bool handleAssignment(EvalInfo &Info, const Expr *E, const LValue &LVal, QualType LValType, APValue &Val) { @@ -8670,6 +9039,25 @@ public: case CK_UserDefinedConversion: return StmtVisitorTy::Visit(E->getSubExpr()); + case CK_HLSLArrayRValue: { + const Expr *SubExpr = E->getSubExpr(); + if (!SubExpr->isGLValue()) { + APValue Val; + if (!Evaluate(Val, Info, SubExpr)) + return false; + return DerivedSuccess(Val, E); + } + + LValue LVal; + if (!EvaluateLValue(SubExpr, LVal, Info)) + return false; + APValue RVal; + // Note, we use the subexpression's type in order to retain cv-qualifiers. + if (!handleLValueToRValueConversion(Info, E, SubExpr->getType(), LVal, + RVal)) + return false; + return DerivedSuccess(RVal, E); + } case CK_LValueToRValue: { LValue LVal; if (!EvaluateLValue(E->getSubExpr(), LVal, Info)) @@ -10854,6 +11242,42 @@ bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) { Result = *Value; return true; } + case CK_HLSLAggregateSplatCast: { + APValue Val; + QualType ValTy; + + if (!hlslAggSplatHelper(Info, E->getSubExpr(), Val, ValTy)) + return false; + + unsigned NEls = elementwiseSize(Info, E->getType()); + // splat our Val + SmallVector<APValue> SplatEls(NEls, Val); + SmallVector<QualType> SplatType(NEls, ValTy); + + // cast the elements and construct our struct result + const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()); + if (!constructAggregate(Info, FPO, E, Result, E->getType(), SplatEls, + SplatType)) + return false; + + return true; + } + case CK_HLSLElementwiseCast: { + SmallVector<APValue> SrcEls; + SmallVector<QualType> SrcTypes; + + if (!hlslElementwiseCastHelper(Info, E->getSubExpr(), E->getType(), SrcEls, + SrcTypes)) + return false; + + // cast the elements and construct our struct result + const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()); + if (!constructAggregate(Info, FPO, E, Result, E->getType(), SrcEls, + SrcTypes)) + return false; + + return true; + } } } @@ -11349,6 +11773,38 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) { Elements.push_back(Val.getVectorElt(I)); return Success(Elements, E); } + case CK_HLSLAggregateSplatCast: { + APValue Val; + QualType ValTy; + + if (!hlslAggSplatHelper(Info, SE, Val, ValTy)) + return false; + + // cast our Val once. + APValue Result; + const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()); + if (!handleScalarCast(Info, FPO, E, ValTy, VTy->getElementType(), Val, + Result)) + return false; + + SmallVector<APValue, 4> SplatEls(NElts, Result); + return Success(SplatEls, E); + } + case CK_HLSLElementwiseCast: { + SmallVector<APValue> SrcVals; + SmallVector<QualType> SrcTypes; + + if (!hlslElementwiseCastHelper(Info, SE, E->getType(), SrcVals, SrcTypes)) + return false; + + const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()); + SmallVector<QualType, 4> DestTypes(NElts, VTy->getElementType()); + SmallVector<APValue, 4> ResultEls(NElts); + if (!handleElementwiseCast(Info, E, FPO, SrcVals, SrcTypes, DestTypes, + ResultEls)) + return false; + return Success(ResultEls, E); + } default: return ExprEvaluatorBaseTy::VisitCastExpr(E); } @@ -13316,6 +13772,7 @@ namespace { bool VisitCallExpr(const CallExpr *E) { return handleCallExpr(E, Result, &This); } + bool VisitCastExpr(const CastExpr *E); bool VisitInitListExpr(const InitListExpr *E, QualType AllocType = QualType()); bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E); @@ -13386,6 +13843,49 @@ static bool MaybeElementDependentArrayFiller(const Expr *FillerExpr) { return true; } +bool ArrayExprEvaluator::VisitCastExpr(const CastExpr *E) { + const Expr *SE = E->getSubExpr(); + + switch (E->getCastKind()) { + default: + return ExprEvaluatorBaseTy::VisitCastExpr(E); + case CK_HLSLAggregateSplatCast: { + APValue Val; + QualType ValTy; + + if (!hlslAggSplatHelper(Info, SE, Val, ValTy)) + return false; + + unsigned NEls = elementwiseSize(Info, E->getType()); + + SmallVector<APValue> SplatEls(NEls, Val); + SmallVector<QualType> SplatType(NEls, ValTy); + + // cast the elements + const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()); + if (!constructAggregate(Info, FPO, E, Result, E->getType(), SplatEls, + SplatType)) + return false; + + return true; + } + case CK_HLSLElementwiseCast: { + SmallVector<APValue> SrcEls; + SmallVector<QualType> SrcTypes; + + if (!hlslElementwiseCastHelper(Info, SE, E->getType(), SrcEls, SrcTypes)) + return false; + + // cast the elements + const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()); + if (!constructAggregate(Info, FPO, E, Result, E->getType(), SrcEls, + SrcTypes)) + return false; + return true; + } + } +} + bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E, QualType AllocType) { const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType( @@ -15744,6 +16244,54 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return Success(Val, E); } + case clang::X86::BI__builtin_ia32_ktestcqi: + case clang::X86::BI__builtin_ia32_ktestchi: + case clang::X86::BI__builtin_ia32_ktestcsi: + case clang::X86::BI__builtin_ia32_ktestcdi: { + APSInt A, B; + if (!EvaluateInteger(E->getArg(0), A, Info) || + !EvaluateInteger(E->getArg(1), B, Info)) + return false; + + return Success((~A & B) == 0, E); + } + + case clang::X86::BI__builtin_ia32_ktestzqi: + case clang::X86::BI__builtin_ia32_ktestzhi: + case clang::X86::BI__builtin_ia32_ktestzsi: + case clang::X86::BI__builtin_ia32_ktestzdi: { + APSInt A, B; + if (!EvaluateInteger(E->getArg(0), A, Info) || + !EvaluateInteger(E->getArg(1), B, Info)) + return false; + + return Success((A & B) == 0, E); + } + + case clang::X86::BI__builtin_ia32_kortestcqi: + case clang::X86::BI__builtin_ia32_kortestchi: + case clang::X86::BI__builtin_ia32_kortestcsi: + case clang::X86::BI__builtin_ia32_kortestcdi: { + APSInt A, B; + if (!EvaluateInteger(E->getArg(0), A, Info) || + !EvaluateInteger(E->getArg(1), B, Info)) + return false; + + return Success(~(A | B) == 0, E); + } + + case clang::X86::BI__builtin_ia32_kortestzqi: + case clang::X86::BI__builtin_ia32_kortestzhi: + case clang::X86::BI__builtin_ia32_kortestzsi: + case clang::X86::BI__builtin_ia32_kortestzdi: { + APSInt A, B; + if (!EvaluateInteger(E->getArg(0), A, Info) || + !EvaluateInteger(E->getArg(1), B, Info)) + return false; + + return Success((A | B) == 0, E); + } + case clang::X86::BI__builtin_ia32_lzcnt_u16: case clang::X86::BI__builtin_ia32_lzcnt_u32: case clang::X86::BI__builtin_ia32_lzcnt_u64: { @@ -17192,7 +17740,6 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_NoOp: case CK_LValueToRValueBitCast: case CK_HLSLArrayRValue: - case CK_HLSLElementwiseCast: return ExprEvaluatorBaseTy::VisitCastExpr(E); case CK_MemberPointerToBoolean: @@ -17339,6 +17886,21 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { return Error(E); return Success(Val.getVectorElt(0), E); } + case CK_HLSLElementwiseCast: { + SmallVector<APValue> SrcVals; + SmallVector<QualType> SrcTypes; + + if (!hlslElementwiseCastHelper(Info, SubExpr, DestType, SrcVals, SrcTypes)) + return false; + + // cast our single element + const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()); + APValue ResultVal; + if (!handleScalarCast(Info, FPO, E, SrcTypes[0], DestType, SrcVals[0], + ResultVal)) + return false; + return Success(ResultVal, E); + } } llvm_unreachable("unknown cast resulting in integral value"); @@ -17876,6 +18438,9 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) { default: return ExprEvaluatorBaseTy::VisitCastExpr(E); + case CK_HLSLAggregateSplatCast: + llvm_unreachable("invalid cast kind for floating value"); + case CK_IntegralToFloating: { APSInt IntResult; const FPOptions FPO = E->getFPFeaturesInEffect( @@ -17914,6 +18479,23 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) { return Error(E); return Success(Val.getVectorElt(0), E); } + case CK_HLSLElementwiseCast: { + SmallVector<APValue> SrcVals; + SmallVector<QualType> SrcTypes; + + if (!hlslElementwiseCastHelper(Info, SubExpr, E->getType(), SrcVals, + SrcTypes)) + return false; + APValue Val; + + // cast our single element + const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()); + APValue ResultVal; + if (!handleScalarCast(Info, FPO, E, SrcTypes[0], E->getType(), SrcVals[0], + ResultVal)) + return false; + return Success(ResultVal, E); + } } } diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index 9f4dba9..89abf88 100644 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -272,15 +272,13 @@ void JSONNodeDumper::writeIncludeStack(PresumedLoc Loc, bool JustFirst) { JOS.attributeEnd(); } -void JSONNodeDumper::writeBareSourceLocation(SourceLocation Loc, - bool IsSpelling) { +void JSONNodeDumper::writeBareSourceLocation(SourceLocation Loc) { PresumedLoc Presumed = SM.getPresumedLoc(Loc); - unsigned ActualLine = IsSpelling ? SM.getSpellingLineNumber(Loc) - : SM.getExpansionLineNumber(Loc); - StringRef ActualFile = SM.getBufferName(Loc); - if (Presumed.isValid()) { - JOS.attribute("offset", SM.getDecomposedLoc(Loc).second); + StringRef ActualFile = SM.getBufferName(Loc); + auto [FID, FilePos] = SM.getDecomposedLoc(Loc); + unsigned ActualLine = SM.getLineNumber(FID, FilePos); + JOS.attribute("offset", FilePos); if (LastLocFilename != ActualFile) { JOS.attribute("file", ActualFile); JOS.attribute("line", ActualLine); @@ -318,18 +316,17 @@ void JSONNodeDumper::writeSourceLocation(SourceLocation Loc) { if (Expansion != Spelling) { // If the expansion and the spelling are different, output subobjects // describing both locations. - JOS.attributeObject("spellingLoc", [Spelling, this] { - writeBareSourceLocation(Spelling, /*IsSpelling*/ true); - }); + JOS.attributeObject( + "spellingLoc", [Spelling, this] { writeBareSourceLocation(Spelling); }); JOS.attributeObject("expansionLoc", [Expansion, Loc, this] { - writeBareSourceLocation(Expansion, /*IsSpelling*/ false); + writeBareSourceLocation(Expansion); // If there is a macro expansion, add extra information if the interesting // bit is the macro arg expansion. if (SM.isMacroArgExpansion(Loc)) JOS.attribute("isMacroArgExpansion", true); }); } else - writeBareSourceLocation(Spelling, /*IsSpelling*/ true); + writeBareSourceLocation(Spelling); } void JSONNodeDumper::writeSourceRange(SourceRange R) { diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index 59d9459..0640fed 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -105,6 +105,8 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { return static_cast<const OMPFilterClause *>(C); case OMPC_ompx_dyn_cgroup_mem: return static_cast<const OMPXDynCGroupMemClause *>(C); + case OMPC_dyn_groupprivate: + return static_cast<const OMPDynGroupprivateClause *>(C); case OMPC_message: return static_cast<const OMPMessageClause *>(C); case OMPC_default: @@ -2857,6 +2859,24 @@ void OMPClausePrinter::VisitOMPXDynCGroupMemClause( OS << ")"; } +void OMPClausePrinter::VisitOMPDynGroupprivateClause( + OMPDynGroupprivateClause *Node) { + OS << "dyn_groupprivate("; + if (Node->getDynGroupprivateModifier() != OMPC_DYN_GROUPPRIVATE_unknown) { + OS << getOpenMPSimpleClauseTypeName(OMPC_dyn_groupprivate, + Node->getDynGroupprivateModifier()); + if (Node->getDynGroupprivateFallbackModifier() != + OMPC_DYN_GROUPPRIVATE_FALLBACK_unknown) { + OS << ", "; + OS << getOpenMPSimpleClauseTypeName( + OMPC_dyn_groupprivate, Node->getDynGroupprivateFallbackModifier()); + } + OS << ": "; + } + Node->getSize()->printPretty(OS, nullptr, Policy, 0); + OS << ')'; +} + void OMPClausePrinter::VisitOMPDoacrossClause(OMPDoacrossClause *Node) { OS << "doacross("; OpenMPDoacrossClauseModifier DepType = Node->getDependenceType(); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index c909e1b..4a8c638 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -968,6 +968,12 @@ void OMPClauseProfiler::VisitOMPXDynCGroupMemClause( if (Expr *Size = C->getSize()) Profiler->VisitStmt(Size); } +void OMPClauseProfiler::VisitOMPDynGroupprivateClause( + const OMPDynGroupprivateClause *C) { + VisitOMPClauseWithPreInit(C); + if (auto *Size = C->getSize()) + Profiler->VisitStmt(Size); +} void OMPClauseProfiler::VisitOMPDoacrossClause(const OMPDoacrossClause *C) { VisitOMPClauseList(C); } diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 549d720..41aebdb 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -2461,7 +2461,6 @@ void TextNodeDumper::VisitVarDecl(const VarDecl *D) { break; case VarDecl::ParenListInit: OS << " parenlistinit"; - break; } } if (D->needsDestruction(D->getASTContext())) @@ -2469,19 +2468,6 @@ void TextNodeDumper::VisitVarDecl(const VarDecl *D) { if (D->isParameterPack()) OS << " pack"; - VarDecl::DefinitionKind K = D->isThisDeclarationADefinition(); - switch (K) { - case VarDecl::DefinitionKind::DeclarationOnly: - OS << " declaration"; - break; - case VarDecl::DefinitionKind::Definition: - OS << " definition"; - break; - case VarDecl::DefinitionKind::TentativeDefinition: - OS << " tentative definition"; - break; - } - if (const auto *Instance = D->getTemplateInstantiationPattern()) { OS << " instantiated_from"; dumpPointer(Instance); diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp index 54c30c0..2f40c7e 100644 --- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp +++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp @@ -238,10 +238,12 @@ const auto isMoveOnly = [] { }; template <class T> struct NodeID; -template <> struct NodeID<Expr> { static constexpr StringRef value = "expr"; }; -template <> struct NodeID<Decl> { static constexpr StringRef value = "decl"; }; -constexpr StringRef NodeID<Expr>::value; -constexpr StringRef NodeID<Decl>::value; +template <> struct NodeID<Expr> { + static constexpr StringRef value = "expr"; +}; +template <> struct NodeID<Decl> { + static constexpr StringRef value = "decl"; +}; template <class T, class F = const Stmt *(ExprMutationAnalyzer::Analyzer::*)(const T *)> diff --git a/clang/lib/Analysis/LifetimeSafety/Dataflow.h b/clang/lib/Analysis/LifetimeSafety/Dataflow.h index 2f7bcb6..de821bb 100644 --- a/clang/lib/Analysis/LifetimeSafety/Dataflow.h +++ b/clang/lib/Analysis/LifetimeSafety/Dataflow.h @@ -67,10 +67,10 @@ private: llvm::DenseMap<const CFGBlock *, Lattice> InStates; /// The dataflow state after a basic block is processed. llvm::DenseMap<const CFGBlock *, Lattice> OutStates; - /// The dataflow state at a Program Point. + /// Dataflow state at each program point, indexed by Fact ID. /// In a forward analysis, this is the state after the Fact at that point has /// been applied, while in a backward analysis, it is the state before. - llvm::DenseMap<ProgramPoint, Lattice> PerPointStates; + llvm::SmallVector<Lattice> PointToState; static constexpr bool isForward() { return Dir == Direction::Forward; } @@ -86,6 +86,8 @@ public: Derived &D = static_cast<Derived &>(*this); llvm::TimeTraceScope Time(D.getAnalysisName()); + PointToState.resize(FactMgr.getNumFacts()); + using Worklist = std::conditional_t<Dir == Direction::Forward, ForwardDataflowWorklist, BackwardDataflowWorklist>; @@ -116,7 +118,9 @@ public: } protected: - Lattice getState(ProgramPoint P) const { return PerPointStates.lookup(P); } + Lattice getState(ProgramPoint P) const { + return PointToState[P->getID().Value]; + } std::optional<Lattice> getInState(const CFGBlock *B) const { auto It = InStates.find(B); @@ -144,12 +148,12 @@ private: if constexpr (isForward()) { for (const Fact *F : Facts) { State = transferFact(State, F); - PerPointStates[F] = State; + PointToState[F->getID().Value] = State; } } else { for (const Fact *F : llvm::reverse(Facts)) { // In backward analysis, capture the state before applying the fact. - PerPointStates[F] = State; + PointToState[F->getID().Value] = State; State = transferFact(State, F); } } diff --git a/clang/lib/Analysis/LifetimeSafety/Facts.cpp b/clang/lib/Analysis/LifetimeSafety/Facts.cpp index 1aea64f..4a4172f 100644 --- a/clang/lib/Analysis/LifetimeSafety/Facts.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Facts.cpp @@ -53,7 +53,7 @@ void ReturnOfOriginFact::dump(llvm::raw_ostream &OS, const LoanManager &, void UseFact::dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM) const { OS << "Use ("; - OM.dump(getUsedOrigin(OM), OS); + OM.dump(getUsedOrigin(), OS); OS << ", " << (isWritten() ? "Write" : "Read") << ")\n"; } @@ -64,8 +64,8 @@ void TestPointFact::dump(llvm::raw_ostream &OS, const LoanManager &, llvm::StringMap<ProgramPoint> FactManager::getTestPoints() const { llvm::StringMap<ProgramPoint> AnnotationToPointMap; - for (const CFGBlock *Block : BlockToFactsMap.keys()) { - for (const Fact *F : getFacts(Block)) { + for (const auto &BlockFacts : BlockToFacts) { + for (const Fact *F : BlockFacts) { if (const auto *TPF = F->getAs<TestPointFact>()) { StringRef PointName = TPF->getAnnotation(); assert(AnnotationToPointMap.find(PointName) == @@ -88,12 +88,9 @@ void FactManager::dump(const CFG &Cfg, AnalysisDeclContext &AC) const { // Print blocks in the order as they appear in code for a stable ordering. for (const CFGBlock *B : *AC.getAnalysis<PostOrderCFGView>()) { llvm::dbgs() << " Block B" << B->getBlockID() << ":\n"; - auto It = BlockToFactsMap.find(B); - if (It != BlockToFactsMap.end()) { - for (const Fact *F : It->second) { - llvm::dbgs() << " "; - F->dump(llvm::dbgs(), LoanMgr, OriginMgr); - } + for (const Fact *F : getFacts(B)) { + llvm::dbgs() << " "; + F->dump(llvm::dbgs(), LoanMgr, OriginMgr); } llvm::dbgs() << " End of Block\n"; } diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index 9b68de1..bec8e1d 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -333,7 +333,7 @@ void FactsGenerator::handleAssignment(const Expr *LHSExpr, // (e.g. on the left-hand side of an assignment). void FactsGenerator::handleUse(const DeclRefExpr *DRE) { if (isPointerType(DRE->getType())) { - UseFact *UF = FactMgr.createFact<UseFact>(DRE); + UseFact *UF = FactMgr.createFact<UseFact>(DRE, FactMgr.getOriginMgr()); CurrentBlockFacts.push_back(UF); assert(!UseFacts.contains(DRE)); UseFacts[DRE] = UF; diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp index 00c7ed90..a51ba42 100644 --- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp @@ -41,6 +41,7 @@ void LifetimeSafetyAnalysis::run() { const CFG &Cfg = *AC.getCFG(); DEBUG_WITH_TYPE("PrintCFG", Cfg.dump(AC.getASTContext().getLangOpts(), /*ShowColors=*/true)); + FactMgr.init(Cfg); FactsGenerator FactGen(FactMgr, AC); FactGen.run(); diff --git a/clang/lib/Analysis/LifetimeSafety/LiveOrigins.cpp b/clang/lib/Analysis/LifetimeSafety/LiveOrigins.cpp index cddb3f3c..59f594e 100644 --- a/clang/lib/Analysis/LifetimeSafety/LiveOrigins.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LiveOrigins.cpp @@ -111,7 +111,7 @@ public: /// dominates this program point. A write operation kills the liveness of /// the origin since it overwrites the value. Lattice transfer(Lattice In, const UseFact &UF) { - OriginID OID = UF.getUsedOrigin(FactMgr.getOriginMgr()); + OriginID OID = UF.getUsedOrigin(); // Write kills liveness. if (UF.isWritten()) return Lattice(Factory.remove(In.LiveOrigins, OID)); diff --git a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp index 387097e..0e6c194 100644 --- a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp @@ -5,36 +5,114 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -#include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h" -#include "Dataflow.h" +#include <cassert> #include <memory> +#include "Dataflow.h" +#include "clang/Analysis/Analyses/LifetimeSafety/Facts.h" +#include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h" +#include "clang/Analysis/Analyses/LifetimeSafety/Loans.h" +#include "clang/Analysis/Analyses/LifetimeSafety/Origins.h" +#include "clang/Analysis/Analyses/LifetimeSafety/Utils.h" +#include "clang/Analysis/AnalysisDeclContext.h" +#include "clang/Analysis/CFG.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/TimeProfiler.h" +#include "llvm/Support/raw_ostream.h" + namespace clang::lifetimes::internal { + +// Prepass to find persistent origins. An origin is persistent if it is +// referenced in more than one basic block. +static llvm::BitVector computePersistentOrigins(const FactManager &FactMgr, + const CFG &C) { + llvm::TimeTraceScope("ComputePersistentOrigins"); + unsigned NumOrigins = FactMgr.getOriginMgr().getNumOrigins(); + llvm::BitVector PersistentOrigins(NumOrigins); + + llvm::SmallVector<const CFGBlock *> OriginToFirstSeenBlock(NumOrigins, + nullptr); + for (const CFGBlock *B : C) { + for (const Fact *F : FactMgr.getFacts(B)) { + auto CheckOrigin = [&](OriginID OID) { + if (PersistentOrigins.test(OID.Value)) + return; + auto &FirstSeenBlock = OriginToFirstSeenBlock[OID.Value]; + if (FirstSeenBlock == nullptr) + FirstSeenBlock = B; + if (FirstSeenBlock != B) { + // We saw this origin in more than one block. + PersistentOrigins.set(OID.Value); + } + }; + + switch (F->getKind()) { + case Fact::Kind::Issue: + CheckOrigin(F->getAs<IssueFact>()->getOriginID()); + break; + case Fact::Kind::OriginFlow: { + const auto *OF = F->getAs<OriginFlowFact>(); + CheckOrigin(OF->getDestOriginID()); + CheckOrigin(OF->getSrcOriginID()); + break; + } + case Fact::Kind::ReturnOfOrigin: + CheckOrigin(F->getAs<ReturnOfOriginFact>()->getReturnedOriginID()); + break; + case Fact::Kind::Use: + CheckOrigin(F->getAs<UseFact>()->getUsedOrigin()); + break; + case Fact::Kind::Expire: + case Fact::Kind::TestPoint: + break; + } + } + } + return PersistentOrigins; +} + namespace { + /// Represents the dataflow lattice for loan propagation. /// /// This lattice tracks which loans each origin may hold at a given program /// point.The lattice has a finite height: An origin's loan set is bounded by /// the total number of loans in the function. -/// TODO(opt): To reduce the lattice size, propagate origins of declarations, -/// not expressions, because expressions are not visible across blocks. struct Lattice { /// The map from an origin to the set of loans it contains. - OriginLoanMap Origins = OriginLoanMap(nullptr); - - explicit Lattice(const OriginLoanMap &S) : Origins(S) {} + /// Origins that appear in multiple blocks. Participates in join operations. + OriginLoanMap PersistentOrigins = OriginLoanMap(nullptr); + /// Origins confined to a single block. Discarded at block boundaries. + OriginLoanMap BlockLocalOrigins = OriginLoanMap(nullptr); + + explicit Lattice(const OriginLoanMap &Persistent, + const OriginLoanMap &BlockLocal) + : PersistentOrigins(Persistent), BlockLocalOrigins(BlockLocal) {} Lattice() = default; bool operator==(const Lattice &Other) const { - return Origins == Other.Origins; + return PersistentOrigins == Other.PersistentOrigins && + BlockLocalOrigins == Other.BlockLocalOrigins; } bool operator!=(const Lattice &Other) const { return !(*this == Other); } void dump(llvm::raw_ostream &OS) const { OS << "LoanPropagationLattice State:\n"; - if (Origins.isEmpty()) + OS << " Persistent Origins:\n"; + if (PersistentOrigins.isEmpty()) OS << " <empty>\n"; - for (const auto &Entry : Origins) { + for (const auto &Entry : PersistentOrigins) { + if (Entry.second.isEmpty()) + OS << " Origin " << Entry.first << " contains no loans\n"; + for (const LoanID &LID : Entry.second) + OS << " Origin " << Entry.first << " contains Loan " << LID << "\n"; + } + OS << " Block-Local Origins:\n"; + if (BlockLocalOrigins.isEmpty()) + OS << " <empty>\n"; + for (const auto &Entry : BlockLocalOrigins) { if (Entry.second.isEmpty()) OS << " Origin " << Entry.first << " contains no loans\n"; for (const LoanID &LID : Entry.second) @@ -50,7 +128,8 @@ public: OriginLoanMap::Factory &OriginLoanMapFactory, LoanSet::Factory &LoanSetFactory) : DataflowAnalysis(C, AC, F), OriginLoanMapFactory(OriginLoanMapFactory), - LoanSetFactory(LoanSetFactory) {} + LoanSetFactory(LoanSetFactory), + PersistentOrigins(computePersistentOrigins(F, C)) {} using Base::transfer; @@ -59,10 +138,10 @@ public: Lattice getInitialState() { return Lattice{}; } /// Merges two lattices by taking the union of loans for each origin. - // TODO(opt): Keep the state small by removing origins which become dead. + /// Only persistent origins are joined; block-local origins are discarded. Lattice join(Lattice A, Lattice B) { OriginLoanMap JoinedOrigins = utils::join( - A.Origins, B.Origins, OriginLoanMapFactory, + A.PersistentOrigins, B.PersistentOrigins, OriginLoanMapFactory, [&](const LoanSet *S1, const LoanSet *S2) { assert((S1 || S2) && "unexpectedly merging 2 empty sets"); if (!S1) @@ -74,16 +153,15 @@ public: // Asymmetric join is a performance win. For origins present only on one // branch, the loan set can be carried over as-is. utils::JoinKind::Asymmetric); - return Lattice(JoinedOrigins); + return Lattice(JoinedOrigins, OriginLoanMapFactory.getEmptyMap()); } /// A new loan is issued to the origin. Old loans are erased. Lattice transfer(Lattice In, const IssueFact &F) { OriginID OID = F.getOriginID(); LoanID LID = F.getLoanID(); - return Lattice(OriginLoanMapFactory.add( - In.Origins, OID, - LoanSetFactory.add(LoanSetFactory.getEmptySet(), LID))); + LoanSet NewLoans = LoanSetFactory.add(LoanSetFactory.getEmptySet(), LID); + return setLoans(In, OID, NewLoans); } /// A flow from source to destination. If `KillDest` is true, this replaces @@ -98,7 +176,7 @@ public: LoanSet SrcLoans = getLoans(In, SrcOID); LoanSet MergedLoans = utils::join(DestLoans, SrcLoans, LoanSetFactory); - return Lattice(OriginLoanMapFactory.add(In.Origins, DestOID, MergedLoans)); + return setLoans(In, DestOID, MergedLoans); } LoanSet getLoans(OriginID OID, ProgramPoint P) const { @@ -106,14 +184,33 @@ public: } private: + /// Returns true if the origin is persistent (referenced in multiple blocks). + bool isPersistent(OriginID OID) const { + return PersistentOrigins.test(OID.Value); + } + + Lattice setLoans(Lattice L, OriginID OID, LoanSet Loans) { + if (isPersistent(OID)) + return Lattice(OriginLoanMapFactory.add(L.PersistentOrigins, OID, Loans), + L.BlockLocalOrigins); + return Lattice(L.PersistentOrigins, + OriginLoanMapFactory.add(L.BlockLocalOrigins, OID, Loans)); + } + LoanSet getLoans(Lattice L, OriginID OID) const { - if (auto *Loans = L.Origins.lookup(OID)) + const OriginLoanMap *Map = + isPersistent(OID) ? &L.PersistentOrigins : &L.BlockLocalOrigins; + if (auto *Loans = Map->lookup(OID)) return *Loans; return LoanSetFactory.getEmptySet(); } OriginLoanMap::Factory &OriginLoanMapFactory; LoanSet::Factory &LoanSetFactory; + /// Boolean vector indexed by origin ID. If true, the origin appears in + /// multiple basic blocks and must participate in join operations. If false, + /// the origin is block-local and can be discarded at block boundaries. + llvm::BitVector PersistentOrigins; }; } // namespace diff --git a/clang/lib/Basic/BuiltinTargetFeatures.h b/clang/lib/Basic/BuiltinTargetFeatures.h index 9754acd..bf227a1 100644 --- a/clang/lib/Basic/BuiltinTargetFeatures.h +++ b/clang/lib/Basic/BuiltinTargetFeatures.h @@ -20,7 +20,7 @@ using llvm::StringRef; namespace clang { namespace Builtin { /// TargetFeatures - This class is used to check whether the builtin function -/// has the required tagert specific features. It is able to support the +/// has the required target specific features. It is able to support the /// combination of ','(and), '|'(or), and '()'. By default, the priority of /// ',' is higher than that of '|' . /// E.g: diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 3d41f2d..8e60fc2 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -196,6 +196,16 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, StringRef Str, return OMPC_GRAINSIZE_unknown; return Type; } + case OMPC_dyn_groupprivate: { + return llvm::StringSwitch<unsigned>(Str) +#define OPENMP_DYN_GROUPPRIVATE_MODIFIER(Name) \ + .Case(#Name, OMPC_DYN_GROUPPRIVATE_##Name) +#define OPENMP_DYN_GROUPPRIVATE_FALLBACK_MODIFIER(Name) \ + .Case(#Name, OMPC_DYN_GROUPPRIVATE_FALLBACK_##Name) \ + .Case("fallback(" #Name ")", OMPC_DYN_GROUPPRIVATE_FALLBACK_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_DYN_GROUPPRIVATE_unknown); + } case OMPC_num_tasks: { unsigned Type = llvm::StringSwitch<unsigned>(Str) #define OPENMP_NUMTASKS_MODIFIER(Name) .Case(#Name, OMPC_NUMTASKS_##Name) @@ -544,6 +554,20 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, #include "clang/Basic/OpenMPKinds.def" } llvm_unreachable("Invalid OpenMP 'grainsize' clause modifier"); + case OMPC_dyn_groupprivate: + switch (Type) { + case OMPC_DYN_GROUPPRIVATE_unknown: + case OMPC_DYN_GROUPPRIVATE_FALLBACK_last: + return "unknown"; +#define OPENMP_DYN_GROUPPRIVATE_MODIFIER(Name) \ + case OMPC_DYN_GROUPPRIVATE_##Name: \ + return #Name; +#define OPENMP_DYN_GROUPPRIVATE_FALLBACK_MODIFIER(Name) \ + case OMPC_DYN_GROUPPRIVATE_FALLBACK_##Name: \ + return "fallback(" #Name ")"; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'dyn_groupprivate' clause modifier"); case OMPC_num_tasks: switch (Type) { case OMPC_NUMTASKS_unknown: diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp index 1eb7199..7bb8c21 100644 --- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp @@ -66,7 +66,7 @@ static mlir::LogicalResult emitStmtWithResult(CIRGenFunction &cgf, mlir::LogicalResult CIRGenFunction::emitCompoundStmtWithoutScope( const CompoundStmt &s, Address *lastValue, AggValueSlot slot) { mlir::LogicalResult result = mlir::success(); - const Stmt *exprResult = s.getStmtExprResult(); + const Stmt *exprResult = s.body_back(); assert((!lastValue || (lastValue && exprResult)) && "If lastValue is not null then the CompoundStmt must have a " "StmtExprResult"); diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index bbcee34..0a2ea41 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -1211,14 +1211,10 @@ llvm::Value *CodeGenFunction::emitCountedByPointerSize( getContext().getTypeSizeInChars(ElementTy->getPointeeType()); if (ElementSize.isZero()) { - // This might be a __sized_by on a 'void *', which counts bytes, not - // elements. - auto *CAT = ElementTy->getAs<CountAttributedType>(); - if (!CAT || (CAT->getKind() != CountAttributedType::SizedBy && - CAT->getKind() != CountAttributedType::SizedByOrNull)) - // Okay, not sure what it is now. - // FIXME: Should this be an assert? - return std::optional<CharUnits>(); + // This might be a __sized_by (or __counted_by) on a + // 'void *', which counts bytes, not elements. + [[maybe_unused]] auto *CAT = ElementTy->getAs<CountAttributedType>(); + assert(CAT && "must have an CountAttributedType"); ElementSize = CharUnits::One(); } diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index fdc1a11..36be329 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -582,48 +582,45 @@ CodeGenFunction::EmitCompoundStmtWithoutScope(const CompoundStmt &S, bool GetLast, AggValueSlot AggSlot) { - const Stmt *ExprResult = S.getStmtExprResult(); - assert((!GetLast || (GetLast && ExprResult)) && - "If GetLast is true then the CompoundStmt must have a StmtExprResult"); + for (CompoundStmt::const_body_iterator I = S.body_begin(), + E = S.body_end() - GetLast; + I != E; ++I) + EmitStmt(*I); Address RetAlloca = Address::invalid(); - - for (auto *CurStmt : S.body()) { - if (GetLast && ExprResult == CurStmt) { - // We have to special case labels here. They are statements, but when put - // at the end of a statement expression, they yield the value of their - // subexpression. Handle this by walking through all labels we encounter, - // emitting them before we evaluate the subexpr. - // Similar issues arise for attributed statements. - while (!isa<Expr>(ExprResult)) { - if (const auto *LS = dyn_cast<LabelStmt>(ExprResult)) { - EmitLabel(LS->getDecl()); - ExprResult = LS->getSubStmt(); - } else if (const auto *AS = dyn_cast<AttributedStmt>(ExprResult)) { - // FIXME: Update this if we ever have attributes that affect the - // semantics of an expression. - ExprResult = AS->getSubStmt(); - } else { - llvm_unreachable("unknown value statement"); - } + if (GetLast) { + // We have to special case labels here. They are statements, but when put + // at the end of a statement expression, they yield the value of their + // subexpression. Handle this by walking through all labels we encounter, + // emitting them before we evaluate the subexpr. + // Similar issues arise for attributed statements. + const Stmt *LastStmt = S.body_back(); + while (!isa<Expr>(LastStmt)) { + if (const auto *LS = dyn_cast<LabelStmt>(LastStmt)) { + EmitLabel(LS->getDecl()); + LastStmt = LS->getSubStmt(); + } else if (const auto *AS = dyn_cast<AttributedStmt>(LastStmt)) { + // FIXME: Update this if we ever have attributes that affect the + // semantics of an expression. + LastStmt = AS->getSubStmt(); + } else { + llvm_unreachable("unknown value statement"); } + } - EnsureInsertPoint(); + EnsureInsertPoint(); - const Expr *E = cast<Expr>(ExprResult); - QualType ExprTy = E->getType(); - if (hasAggregateEvaluationKind(ExprTy)) { - EmitAggExpr(E, AggSlot); - } else { - // We can't return an RValue here because there might be cleanups at - // the end of the StmtExpr. Because of that, we have to emit the result - // here into a temporary alloca. - RetAlloca = CreateMemTemp(ExprTy); - EmitAnyExprToMem(E, RetAlloca, Qualifiers(), - /*IsInit*/ false); - } + const Expr *E = cast<Expr>(LastStmt); + QualType ExprTy = E->getType(); + if (hasAggregateEvaluationKind(ExprTy)) { + EmitAggExpr(E, AggSlot); } else { - EmitStmt(CurStmt); + // We can't return an RValue here because there might be cleanups at + // the end of the StmtExpr. Because of that, we have to emit the result + // here into a temporary alloca. + RetAlloca = CreateMemTemp(ExprTy); + EmitAnyExprToMem(E, RetAlloca, Qualifiers(), + /*IsInit*/ false); } } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 0fea57b..98d59b7 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2368,9 +2368,8 @@ static QualType GeneralizeTransparentUnion(QualType Ty) { const RecordDecl *UD = UT->getDecl()->getDefinitionOrSelf(); if (!UD->hasAttr<TransparentUnionAttr>()) return Ty; - for (const auto *it : UD->fields()) { - return it->getType(); - } + if (!UD->fields().empty()) + return UD->fields().begin()->getType(); return Ty; } diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp index 8f09564..06d7380 100644 --- a/clang/lib/CodeGen/CodeGenPGO.cpp +++ b/clang/lib/CodeGen/CodeGenPGO.cpp @@ -58,9 +58,10 @@ enum PGOHashVersion : unsigned { PGO_HASH_V1, PGO_HASH_V2, PGO_HASH_V3, + PGO_HASH_V4, // Keep this set to the latest hash version. - PGO_HASH_LATEST = PGO_HASH_V3 + PGO_HASH_LATEST = PGO_HASH_V4 }; namespace { @@ -152,7 +153,9 @@ static PGOHashVersion getPGOHashVersion(llvm::IndexedInstrProfReader *PGOReader, return PGO_HASH_V1; if (PGOReader->getVersion() <= 5) return PGO_HASH_V2; - return PGO_HASH_V3; + if (PGOReader->getVersion() <= 12) + return PGO_HASH_V3; + return PGO_HASH_V4; } /// A RecursiveASTVisitor that fills a map of statements to PGO counters. @@ -1099,6 +1102,8 @@ void CodeGenPGO::mapRegionCounters(const Decl *D) { assert(Walker.NextCounter > 0 && "no entry counter mapped for decl"); NumRegionCounters = Walker.NextCounter; FunctionHash = Walker.Hash.finalize(); + if (HashVersion >= PGO_HASH_V4) + FunctionHash &= llvm::NamedInstrProfRecord::FUNC_HASH_MASK; } bool CodeGenPGO::skipRegionMappingForDecl(const Decl *D) { diff --git a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp index 15fa78d..d4b0b81 100644 --- a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp @@ -590,6 +590,7 @@ struct ARMVectorIntrinsicInfo { Intrinsic::LLVMIntrinsic, Intrinsic::AltLLVMIntrinsic, \ TypeModifier } +// clang-format off static const ARMVectorIntrinsicInfo ARMSIMDIntrinsicMap [] = { NEONMAP1(__a32_vcvt_bf16_f32, arm_neon_vcvtfp2bf, 0), NEONMAP0(splat_lane_v), @@ -1217,35 +1218,55 @@ static const ARMVectorIntrinsicInfo AArch64SISDIntrinsicMap[] = { NEONMAP1(vcales_f32, aarch64_neon_facge, AddRetType | Add1ArgType), NEONMAP1(vcaltd_f64, aarch64_neon_facgt, AddRetType | Add1ArgType), NEONMAP1(vcalts_f32, aarch64_neon_facgt, AddRetType | Add1ArgType), + NEONMAP1(vcvtad_s32_f64, aarch64_neon_fcvtas, AddRetType | Add1ArgType), NEONMAP1(vcvtad_s64_f64, aarch64_neon_fcvtas, AddRetType | Add1ArgType), + NEONMAP1(vcvtad_u32_f64, aarch64_neon_fcvtau, AddRetType | Add1ArgType), NEONMAP1(vcvtad_u64_f64, aarch64_neon_fcvtau, AddRetType | Add1ArgType), NEONMAP1(vcvtas_s32_f32, aarch64_neon_fcvtas, AddRetType | Add1ArgType), + NEONMAP1(vcvtas_s64_f32, aarch64_neon_fcvtas, AddRetType | Add1ArgType), NEONMAP1(vcvtas_u32_f32, aarch64_neon_fcvtau, AddRetType | Add1ArgType), + NEONMAP1(vcvtas_u64_f32, aarch64_neon_fcvtau, AddRetType | Add1ArgType), NEONMAP1(vcvtd_n_f64_s64, aarch64_neon_vcvtfxs2fp, AddRetType | Add1ArgType), NEONMAP1(vcvtd_n_f64_u64, aarch64_neon_vcvtfxu2fp, AddRetType | Add1ArgType), NEONMAP1(vcvtd_n_s64_f64, aarch64_neon_vcvtfp2fxs, AddRetType | Add1ArgType), NEONMAP1(vcvtd_n_u64_f64, aarch64_neon_vcvtfp2fxu, AddRetType | Add1ArgType), + NEONMAP1(vcvtd_s32_f64, aarch64_neon_fcvtzs, AddRetType | Add1ArgType), NEONMAP1(vcvtd_s64_f64, aarch64_neon_fcvtzs, AddRetType | Add1ArgType), + NEONMAP1(vcvtd_u32_f64, aarch64_neon_fcvtzu, AddRetType | Add1ArgType), NEONMAP1(vcvtd_u64_f64, aarch64_neon_fcvtzu, AddRetType | Add1ArgType), NEONMAP0(vcvth_bf16_f32), + NEONMAP1(vcvtmd_s32_f64, aarch64_neon_fcvtms, AddRetType | Add1ArgType), NEONMAP1(vcvtmd_s64_f64, aarch64_neon_fcvtms, AddRetType | Add1ArgType), + NEONMAP1(vcvtmd_u32_f64, aarch64_neon_fcvtmu, AddRetType | Add1ArgType), NEONMAP1(vcvtmd_u64_f64, aarch64_neon_fcvtmu, AddRetType | Add1ArgType), NEONMAP1(vcvtms_s32_f32, aarch64_neon_fcvtms, AddRetType | Add1ArgType), + NEONMAP1(vcvtms_s64_f32, aarch64_neon_fcvtms, AddRetType | Add1ArgType), NEONMAP1(vcvtms_u32_f32, aarch64_neon_fcvtmu, AddRetType | Add1ArgType), + NEONMAP1(vcvtms_u64_f32, aarch64_neon_fcvtmu, AddRetType | Add1ArgType), + NEONMAP1(vcvtnd_s32_f64, aarch64_neon_fcvtns, AddRetType | Add1ArgType), NEONMAP1(vcvtnd_s64_f64, aarch64_neon_fcvtns, AddRetType | Add1ArgType), + NEONMAP1(vcvtnd_u32_f64, aarch64_neon_fcvtnu, AddRetType | Add1ArgType), NEONMAP1(vcvtnd_u64_f64, aarch64_neon_fcvtnu, AddRetType | Add1ArgType), NEONMAP1(vcvtns_s32_f32, aarch64_neon_fcvtns, AddRetType | Add1ArgType), + NEONMAP1(vcvtns_s64_f32, aarch64_neon_fcvtns, AddRetType | Add1ArgType), NEONMAP1(vcvtns_u32_f32, aarch64_neon_fcvtnu, AddRetType | Add1ArgType), + NEONMAP1(vcvtns_u64_f32, aarch64_neon_fcvtnu, AddRetType | Add1ArgType), + NEONMAP1(vcvtpd_s32_f64, aarch64_neon_fcvtps, AddRetType | Add1ArgType), NEONMAP1(vcvtpd_s64_f64, aarch64_neon_fcvtps, AddRetType | Add1ArgType), + NEONMAP1(vcvtpd_u32_f64, aarch64_neon_fcvtpu, AddRetType | Add1ArgType), NEONMAP1(vcvtpd_u64_f64, aarch64_neon_fcvtpu, AddRetType | Add1ArgType), NEONMAP1(vcvtps_s32_f32, aarch64_neon_fcvtps, AddRetType | Add1ArgType), + NEONMAP1(vcvtps_s64_f32, aarch64_neon_fcvtps, AddRetType | Add1ArgType), NEONMAP1(vcvtps_u32_f32, aarch64_neon_fcvtpu, AddRetType | Add1ArgType), + NEONMAP1(vcvtps_u64_f32, aarch64_neon_fcvtpu, AddRetType | Add1ArgType), NEONMAP1(vcvts_n_f32_s32, aarch64_neon_vcvtfxs2fp, AddRetType | Add1ArgType), NEONMAP1(vcvts_n_f32_u32, aarch64_neon_vcvtfxu2fp, AddRetType | Add1ArgType), NEONMAP1(vcvts_n_s32_f32, aarch64_neon_vcvtfp2fxs, AddRetType | Add1ArgType), NEONMAP1(vcvts_n_u32_f32, aarch64_neon_vcvtfp2fxu, AddRetType | Add1ArgType), NEONMAP1(vcvts_s32_f32, aarch64_neon_fcvtzs, AddRetType | Add1ArgType), + NEONMAP1(vcvts_s64_f32, aarch64_neon_fcvtzs, AddRetType | Add1ArgType), NEONMAP1(vcvts_u32_f32, aarch64_neon_fcvtzu, AddRetType | Add1ArgType), + NEONMAP1(vcvts_u64_f32, aarch64_neon_fcvtzu, AddRetType | Add1ArgType), NEONMAP1(vcvtxd_f32_f64, aarch64_sisd_fcvtxn, 0), NEONMAP1(vmaxnmv_f32, aarch64_neon_fmaxnmv, AddRetType | Add1ArgType), NEONMAP1(vmaxnmvq_f32, aarch64_neon_fmaxnmv, AddRetType | Add1ArgType), @@ -1446,6 +1467,7 @@ static const ARMVectorIntrinsicInfo AArch64SISDIntrinsicMap[] = { NEONMAP1(vrsqrteh_f16, aarch64_neon_frsqrte, Add1ArgType), NEONMAP1(vrsqrtsh_f16, aarch64_neon_frsqrts, Add1ArgType), }; +// clang-format on // Some intrinsics are equivalent for codegen. static const std::pair<unsigned, unsigned> NEONEquivalentIntrinsicMap[] = { @@ -7624,6 +7646,16 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, Int = Intrinsic::aarch64_neon_vluti4q_laneq_x2; return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vluti4q_laneq_x2"); } + case NEON::BI__builtin_neon_vmmlaq_f16_mf8_fpm: + return EmitFP8NeonCall(Intrinsic::aarch64_neon_fmmla, + {llvm::FixedVectorType::get(HalfTy, 8), + llvm::FixedVectorType::get(Int8Ty, 16)}, + Ops, E, "fmmla"); + case NEON::BI__builtin_neon_vmmlaq_f32_mf8_fpm: + return EmitFP8NeonCall(Intrinsic::aarch64_neon_fmmla, + {llvm::FixedVectorType::get(FloatTy, 4), + llvm::FixedVectorType::get(Int8Ty, 16)}, + Ops, E, "fmmla"); case NEON::BI__builtin_neon_vcvt1_low_bf16_mf8_fpm: ExtractLow = true; [[fallthrough]]; diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp index bb41a14..d42fcd8 100644 --- a/clang/lib/CodeGen/Targets/AArch64.cpp +++ b/clang/lib/CodeGen/Targets/AArch64.cpp @@ -422,6 +422,12 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadicFn, } // Empty records: + // AAPCS64 does not say that empty records are ignored as arguments, + // but other compilers do so in certain situations, and we copy that behavior. + // Those situations are in fact language-mode-specific, which seems really + // unfortunate, but it's something we just have to accept. If this doesn't + // apply, just fall through to the standard argument-handling path. + // Darwin overrides the psABI here to ignore all empty records in all modes. uint64_t Size = getContext().getTypeSize(Ty); bool IsEmpty = isEmptyRecord(getContext(), Ty, true); if (!Ty->isSVESizelessBuiltinType() && (IsEmpty || Size == 0)) { @@ -434,9 +440,6 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadicFn, // behaviour here. if (Size == 0) return ABIArgInfo::getIgnore(); - - // Otherwise, they are passed as if they have a size of 1 byte. - return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext())); } // Homogeneous Floating-point Aggregates (HFAs) need to be expanded. diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp index 654a382..1a243fe 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -22,6 +22,7 @@ #include "llvm/Support/Process.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/TargetParser.h" #include <optional> #include <system_error> @@ -1095,9 +1096,21 @@ bool AMDGPUToolChain::shouldSkipSanitizeOption( if (K != SanitizerKind::Address) return true; + // Check 'xnack+' availability by default + llvm::StringRef Processor = + getProcessorFromTargetID(TC.getTriple(), TargetID); + auto ProcKind = TC.getTriple().isAMDGCN() + ? llvm::AMDGPU::parseArchAMDGCN(Processor) + : llvm::AMDGPU::parseArchR600(Processor); + auto Features = TC.getTriple().isAMDGCN() + ? llvm::AMDGPU::getArchAttrAMDGCN(ProcKind) + : llvm::AMDGPU::getArchAttrR600(ProcKind); + if (Features & llvm::AMDGPU::FEATURE_XNACK_ALWAYS) + return false; + + // Look for the xnack feature in TargetID llvm::StringMap<bool> FeatureMap; auto OptionalGpuArch = parseTargetID(TC.getTriple(), TargetID, &FeatureMap); - assert(OptionalGpuArch && "Invalid Target ID"); (void)OptionalGpuArch; auto Loc = FeatureMap.find("xnack"); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 30d3e52..e20963a 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -8266,6 +8266,30 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, << "/kernel"; } + if (const Arg *A = Args.getLastArg(options::OPT__SLASH_vlen, + options::OPT__SLASH_vlen_EQ_256, + options::OPT__SLASH_vlen_EQ_512)) { + llvm::Triple::ArchType AT = getToolChain().getArch(); + StringRef Default = AT == llvm::Triple::x86 ? "IA32" : "SSE2"; + StringRef Arch = Args.getLastArgValue(options::OPT__SLASH_arch, Default); + + if (A->getOption().matches(options::OPT__SLASH_vlen_EQ_512)) { + if (Arch == "AVX512F" || Arch == "AVX512") + CmdArgs.push_back("-mprefer-vector-width=512"); + else + D.Diag(diag::warn_drv_argument_not_allowed_with) + << "/vlen=512" << std::string("/arch:").append(Arch); + } + + if (A->getOption().matches(options::OPT__SLASH_vlen_EQ_256)) { + if (Arch == "AVX512F" || Arch == "AVX512") + CmdArgs.push_back("-mprefer-vector-width=256"); + else if (Arch != "AVX" && Arch != "AVX2") + D.Diag(diag::warn_drv_argument_not_allowed_with) + << "/vlen=256" << std::string("/arch:").append(Arch); + } + } + Arg *MostGeneralArg = Args.getLastArg(options::OPT__SLASH_vmg); Arg *BestCaseArg = Args.getLastArg(options::OPT__SLASH_vmb); if (MostGeneralArg && BestCaseArg) diff --git a/clang/lib/Driver/ToolChains/HLSL.cpp b/clang/lib/Driver/ToolChains/HLSL.cpp index 8d3fba7..5d7221b 100644 --- a/clang/lib/Driver/ToolChains/HLSL.cpp +++ b/clang/lib/Driver/ToolChains/HLSL.cpp @@ -567,3 +567,7 @@ bool HLSLToolChain::isLastJob(DerivedArgList &Args, // output to the result file. return true; } + +void HLSLToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { + CC1Args.push_back("-Wconversion"); +} diff --git a/clang/lib/Driver/ToolChains/HLSL.h b/clang/lib/Driver/ToolChains/HLSL.h index 3aed904..5bf385e 100644 --- a/clang/lib/Driver/ToolChains/HLSL.h +++ b/clang/lib/Driver/ToolChains/HLSL.h @@ -91,6 +91,8 @@ public: // Set default DWARF version to 4 for DXIL uses version 4. unsigned GetDefaultDwarfVersion() const override { return 4; } + void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override; + private: mutable std::unique_ptr<tools::hlsl::Validator> Validator; mutable std::unique_ptr<tools::hlsl::MetalConverter> MetalConverter; diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index dd14fcd..9bbb33c 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -876,27 +876,28 @@ template <> struct MappingTraits<FormatStyle::TrailingCommentsAlignmentStyle> { FormatStyle::TrailingCommentsAlignmentStyle &Value) { IO.enumCase(Value, "Leave", FormatStyle::TrailingCommentsAlignmentStyle( - {FormatStyle::TCAS_Leave, 0})); + {FormatStyle::TCAS_Leave, 0, true})); IO.enumCase(Value, "Always", FormatStyle::TrailingCommentsAlignmentStyle( - {FormatStyle::TCAS_Always, 0})); + {FormatStyle::TCAS_Always, 0, true})); IO.enumCase(Value, "Never", FormatStyle::TrailingCommentsAlignmentStyle( - {FormatStyle::TCAS_Never, 0})); + {FormatStyle::TCAS_Never, 0, true})); // For backwards compatibility IO.enumCase(Value, "true", FormatStyle::TrailingCommentsAlignmentStyle( - {FormatStyle::TCAS_Always, 0})); + {FormatStyle::TCAS_Always, 0, true})); IO.enumCase(Value, "false", FormatStyle::TrailingCommentsAlignmentStyle( - {FormatStyle::TCAS_Never, 0})); + {FormatStyle::TCAS_Never, 0, true})); } static void mapping(IO &IO, FormatStyle::TrailingCommentsAlignmentStyle &Value) { + IO.mapOptional("AlignPPAndNotPP", Value.AlignPPAndNotPP); IO.mapOptional("Kind", Value.Kind); IO.mapOptional("OverEmptyLines", Value.OverEmptyLines); } @@ -1651,6 +1652,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.AlignTrailingComments = {}; LLVMStyle.AlignTrailingComments.Kind = FormatStyle::TCAS_Always; LLVMStyle.AlignTrailingComments.OverEmptyLines = 0; + LLVMStyle.AlignTrailingComments.AlignPPAndNotPP = true; LLVMStyle.AllowAllArgumentsOnNextLine = true; LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true; LLVMStyle.AllowBreakBeforeNoexceptSpecifier = FormatStyle::BBNSS_Never; diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index 406c77c..fece384 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -1007,9 +1007,13 @@ void WhitespaceManager::alignTrailingComments() { return; const int Size = Changes.size(); + if (Size == 0) + return; + int MinColumn = 0; int StartOfSequence = 0; bool BreakBeforeNext = false; + bool IsInPP = Changes.front().Tok->Tok.is(tok::hash); int NewLineThreshold = 1; if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Always) NewLineThreshold = Style.AlignTrailingComments.OverEmptyLines + 1; @@ -1018,7 +1022,19 @@ void WhitespaceManager::alignTrailingComments() { auto &C = Changes[I]; if (C.StartOfBlockComment) continue; - Newlines += C.NewlinesBefore; + if (C.NewlinesBefore != 0) { + Newlines += C.NewlinesBefore; + const bool WasInPP = std::exchange( + IsInPP, C.Tok->Tok.is(tok::hash) || (IsInPP && C.IsTrailingComment) || + C.ContinuesPPDirective); + if (IsInPP != WasInPP && !Style.AlignTrailingComments.AlignPPAndNotPP) { + alignTrailingComments(StartOfSequence, I, MinColumn); + MinColumn = 0; + MaxColumn = INT_MAX; + StartOfSequence = I; + Newlines = 0; + } + } if (!C.IsTrailingComment) continue; diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 6b09f7f..8034ce9 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1058,7 +1058,9 @@ void CompilerInstance::printDiagnosticStats() { if (!getLangOpts().CUDAIsDevice) { OS << " when compiling for host"; } else { - OS << " when compiling for " << getTargetOpts().CPU; + OS << " when compiling for " + << (!getTargetOpts().CPU.empty() ? getTargetOpts().CPU + : getTarget().getTriple().str()); } } OS << ".\n"; diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index d7d56b8..3595bbc 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -1233,20 +1233,6 @@ void PrintDependencyDirectivesSourceMinimizerAction::ExecuteAction() { llvm::outs()); } -void GetDependenciesByModuleNameAction::ExecuteAction() { - CompilerInstance &CI = getCompilerInstance(); - Preprocessor &PP = CI.getPreprocessor(); - SourceManager &SM = PP.getSourceManager(); - FileID MainFileID = SM.getMainFileID(); - SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID); - SmallVector<IdentifierLoc, 2> Path; - IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName); - Path.emplace_back(FileStart, ModuleID); - auto ModResult = CI.loadModule(FileStart, Path, Module::Hidden, false); - PPCallbacks *CB = PP.getPPCallbacks(); - CB->moduleImport(SourceLocation(), Path, ModResult); -} - //===----------------------------------------------------------------------===// // HLSL Specific Actions //===----------------------------------------------------------------------===// diff --git a/clang/lib/Headers/avx512bwintrin.h b/clang/lib/Headers/avx512bwintrin.h index aab1f2b..203b600 100644 --- a/clang/lib/Headers/avx512bwintrin.h +++ b/clang/lib/Headers/avx512bwintrin.h @@ -92,69 +92,65 @@ _kxor_mask64(__mmask64 __A, __mmask64 __B) { return (__mmask64)__builtin_ia32_kxordi((__mmask64)__A, (__mmask64)__B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS -_kortestc_mask32_u8(__mmask32 __A, __mmask32 __B) -{ +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR +_kortestc_mask32_u8(__mmask32 __A, __mmask32 __B) { return (unsigned char)__builtin_ia32_kortestcsi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS -_kortestz_mask32_u8(__mmask32 __A, __mmask32 __B) -{ +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR +_kortestz_mask32_u8(__mmask32 __A, __mmask32 __B) { return (unsigned char)__builtin_ia32_kortestzsi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR _kortest_mask32_u8(__mmask32 __A, __mmask32 __B, unsigned char *__C) { *__C = (unsigned char)__builtin_ia32_kortestcsi(__A, __B); return (unsigned char)__builtin_ia32_kortestzsi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR _kortestc_mask64_u8(__mmask64 __A, __mmask64 __B) { return (unsigned char)__builtin_ia32_kortestcdi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR _kortestz_mask64_u8(__mmask64 __A, __mmask64 __B) { return (unsigned char)__builtin_ia32_kortestzdi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR _kortest_mask64_u8(__mmask64 __A, __mmask64 __B, unsigned char *__C) { *__C = (unsigned char)__builtin_ia32_kortestcdi(__A, __B); return (unsigned char)__builtin_ia32_kortestzdi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS -_ktestc_mask32_u8(__mmask32 __A, __mmask32 __B) -{ +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR +_ktestc_mask32_u8(__mmask32 __A, __mmask32 __B) { return (unsigned char)__builtin_ia32_ktestcsi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS -_ktestz_mask32_u8(__mmask32 __A, __mmask32 __B) -{ +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR +_ktestz_mask32_u8(__mmask32 __A, __mmask32 __B) { return (unsigned char)__builtin_ia32_ktestzsi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR _ktest_mask32_u8(__mmask32 __A, __mmask32 __B, unsigned char *__C) { *__C = (unsigned char)__builtin_ia32_ktestcsi(__A, __B); return (unsigned char)__builtin_ia32_ktestzsi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR _ktestc_mask64_u8(__mmask64 __A, __mmask64 __B) { return (unsigned char)__builtin_ia32_ktestcdi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR _ktestz_mask64_u8(__mmask64 __A, __mmask64 __B) { return (unsigned char)__builtin_ia32_ktestzdi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR _ktest_mask64_u8(__mmask64 __A, __mmask64 __B, unsigned char *__C) { *__C = (unsigned char)__builtin_ia32_ktestcdi(__A, __B); return (unsigned char)__builtin_ia32_ktestzdi(__A, __B); diff --git a/clang/lib/Headers/avx512cdintrin.h b/clang/lib/Headers/avx512cdintrin.h index fb6dcb6..f9de207 100644 --- a/clang/lib/Headers/avx512cdintrin.h +++ b/clang/lib/Headers/avx512cdintrin.h @@ -17,8 +17,8 @@ /* Define the default attributes for the functions in this file. */ #if defined(__cplusplus) && (__cplusplus >= 201103L) #define __DEFAULT_FN_ATTRS \ - constexpr __attribute__((__always_inline__, __nodebug__, \ - __target__("avx512cd"), __min_vector_width__(512))) + __attribute__((__always_inline__, __nodebug__, __target__("avx512cd"), \ + __min_vector_width__(512))) constexpr #else #define __DEFAULT_FN_ATTRS \ __attribute__((__always_inline__, __nodebug__, __target__("avx512cd"), \ diff --git a/clang/lib/Headers/avx512dqintrin.h b/clang/lib/Headers/avx512dqintrin.h index fef1a2d..29156e7 100644 --- a/clang/lib/Headers/avx512dqintrin.h +++ b/clang/lib/Headers/avx512dqintrin.h @@ -59,55 +59,49 @@ _kxor_mask8(__mmask8 __A, __mmask8 __B) { return (__mmask8)__builtin_ia32_kxorqi((__mmask8)__A, (__mmask8)__B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS -_kortestc_mask8_u8(__mmask8 __A, __mmask8 __B) -{ +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR +_kortestc_mask8_u8(__mmask8 __A, __mmask8 __B) { return (unsigned char)__builtin_ia32_kortestcqi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS -_kortestz_mask8_u8(__mmask8 __A, __mmask8 __B) -{ +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR +_kortestz_mask8_u8(__mmask8 __A, __mmask8 __B) { return (unsigned char)__builtin_ia32_kortestzqi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR _kortest_mask8_u8(__mmask8 __A, __mmask8 __B, unsigned char *__C) { *__C = (unsigned char)__builtin_ia32_kortestcqi(__A, __B); return (unsigned char)__builtin_ia32_kortestzqi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS -_ktestc_mask8_u8(__mmask8 __A, __mmask8 __B) -{ +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR +_ktestc_mask8_u8(__mmask8 __A, __mmask8 __B) { return (unsigned char)__builtin_ia32_ktestcqi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS -_ktestz_mask8_u8(__mmask8 __A, __mmask8 __B) -{ +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR +_ktestz_mask8_u8(__mmask8 __A, __mmask8 __B) { return (unsigned char)__builtin_ia32_ktestzqi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR _ktest_mask8_u8(__mmask8 __A, __mmask8 __B, unsigned char *__C) { *__C = (unsigned char)__builtin_ia32_ktestcqi(__A, __B); return (unsigned char)__builtin_ia32_ktestzqi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS -_ktestc_mask16_u8(__mmask16 __A, __mmask16 __B) -{ +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR +_ktestc_mask16_u8(__mmask16 __A, __mmask16 __B) { return (unsigned char)__builtin_ia32_ktestchi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS -_ktestz_mask16_u8(__mmask16 __A, __mmask16 __B) -{ +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR +_ktestz_mask16_u8(__mmask16 __A, __mmask16 __B) { return (unsigned char)__builtin_ia32_ktestzhi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR _ktest_mask16_u8(__mmask16 __A, __mmask16 __B, unsigned char *__C) { *__C = (unsigned char)__builtin_ia32_ktestchi(__A, __B); return (unsigned char)__builtin_ia32_ktestzhi(__A, __B); diff --git a/clang/lib/Headers/avx512fintrin.h b/clang/lib/Headers/avx512fintrin.h index 5fc0afa..997e960 100644 --- a/clang/lib/Headers/avx512fintrin.h +++ b/clang/lib/Headers/avx512fintrin.h @@ -8068,31 +8068,27 @@ _mm512_kor(__mmask16 __A, __mmask16 __B) { return (__mmask16) __builtin_ia32_korhi ((__mmask16) __A, (__mmask16) __B); } -static __inline__ int __DEFAULT_FN_ATTRS -_mm512_kortestc (__mmask16 __A, __mmask16 __B) -{ +static __inline__ int __DEFAULT_FN_ATTRS_CONSTEXPR +_mm512_kortestc(__mmask16 __A, __mmask16 __B) { return __builtin_ia32_kortestchi ((__mmask16) __A, (__mmask16) __B); } -static __inline__ int __DEFAULT_FN_ATTRS -_mm512_kortestz (__mmask16 __A, __mmask16 __B) -{ +static __inline__ int __DEFAULT_FN_ATTRS_CONSTEXPR +_mm512_kortestz(__mmask16 __A, __mmask16 __B) { return __builtin_ia32_kortestzhi ((__mmask16) __A, (__mmask16) __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS -_kortestc_mask16_u8(__mmask16 __A, __mmask16 __B) -{ +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR +_kortestc_mask16_u8(__mmask16 __A, __mmask16 __B) { return (unsigned char)__builtin_ia32_kortestchi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS -_kortestz_mask16_u8(__mmask16 __A, __mmask16 __B) -{ +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR +_kortestz_mask16_u8(__mmask16 __A, __mmask16 __B) { return (unsigned char)__builtin_ia32_kortestzhi(__A, __B); } -static __inline__ unsigned char __DEFAULT_FN_ATTRS +static __inline__ unsigned char __DEFAULT_FN_ATTRS_CONSTEXPR _kortest_mask16_u8(__mmask16 __A, __mmask16 __B, unsigned char *__C) { *__C = (unsigned char)__builtin_ia32_kortestchi(__A, __B); return (unsigned char)__builtin_ia32_kortestzhi(__A, __B); diff --git a/clang/lib/Headers/avx512vlcdintrin.h b/clang/lib/Headers/avx512vlcdintrin.h index 7719680f..df66e1d 100644 --- a/clang/lib/Headers/avx512vlcdintrin.h +++ b/clang/lib/Headers/avx512vlcdintrin.h @@ -16,13 +16,13 @@ /* Define the default attributes for the functions in this file. */ #if defined(__cplusplus) && (__cplusplus >= 201103L) #define __DEFAULT_FN_ATTRS128 \ - constexpr __attribute__((__always_inline__, __nodebug__, \ - __target__("avx512vl,avx512cd"), \ - __min_vector_width__(128))) + __attribute__((__always_inline__, __nodebug__, \ + __target__("avx512vl,avx512cd"), \ + __min_vector_width__(128))) constexpr #define __DEFAULT_FN_ATTRS256 \ - constexpr __attribute__((__always_inline__, __nodebug__, \ - __target__("avx512vl,avx512cd"), \ - __min_vector_width__(256))) + __attribute__((__always_inline__, __nodebug__, \ + __target__("avx512vl,avx512cd"), \ + __min_vector_width__(256))) constexpr #else #define __DEFAULT_FN_ATTRS128 \ __attribute__((__always_inline__, __nodebug__, \ diff --git a/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h index 208776e..2e2703d 100644 --- a/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h @@ -1074,78 +1074,6 @@ _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_f16tof32) float4 f16tof32(uint4); //===----------------------------------------------------------------------===// -// firstbithigh builtins -//===----------------------------------------------------------------------===// - -/// \fn T firstbithigh(T Val) -/// \brief Returns the location of the first set bit starting from the highest -/// order bit and working downward, per component. -/// \param Val the input value. - -#ifdef __HLSL_ENABLE_16_BIT -_HLSL_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint firstbithigh(int16_t); -_HLSL_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint2 firstbithigh(int16_t2); -_HLSL_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint3 firstbithigh(int16_t3); -_HLSL_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint4 firstbithigh(int16_t4); -_HLSL_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint firstbithigh(uint16_t); -_HLSL_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint2 firstbithigh(uint16_t2); -_HLSL_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint3 firstbithigh(uint16_t3); -_HLSL_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint4 firstbithigh(uint16_t4); -#endif - -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint firstbithigh(int); -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint2 firstbithigh(int2); -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint3 firstbithigh(int3); -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint4 firstbithigh(int4); - -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint firstbithigh(uint); -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint2 firstbithigh(uint2); -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint3 firstbithigh(uint3); -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint4 firstbithigh(uint4); - -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint firstbithigh(int64_t); -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint2 firstbithigh(int64_t2); -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint3 firstbithigh(int64_t3); -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint4 firstbithigh(int64_t4); - -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint firstbithigh(uint64_t); -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint2 firstbithigh(uint64_t2); -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint3 firstbithigh(uint64_t3); -_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) -uint4 firstbithigh(uint64_t4); - -//===----------------------------------------------------------------------===// // firstbitlow builtins //===----------------------------------------------------------------------===// diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h index c877234..3d8fe7e 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h @@ -148,6 +148,18 @@ template <typename T> constexpr T ldexp_impl(T X, T Exp) { return exp2(Exp) * X; } +template <typename K, typename T, int BitWidth> +constexpr K firstbithigh_impl(T X) { + K FBH = __builtin_hlsl_elementwise_firstbithigh(X); +#if defined(__DIRECTX__) + // The firstbithigh DXIL ops count bits from the wrong side, so we need to + // invert it for DirectX. + K Inversion = (BitWidth - 1) - FBH; + FBH = select(FBH == -1, FBH, Inversion); +#endif + return FBH; +} + } // namespace __detail } // namespace hlsl diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 5ba5bfb..33ed143 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -262,6 +262,67 @@ faceforward(__detail::HLSL_FIXED_VECTOR<float, L> N, } //===----------------------------------------------------------------------===// +// firstbithigh builtins +//===----------------------------------------------------------------------===// + +/// \fn T firstbithigh(T Val) +/// \brief Returns the location of the first set bit starting from the lowest +/// order bit and working upward, per component. +/// \param Val the input value. + +#ifdef __HLSL_ENABLE_16_BIT + +template <typename T> +_HLSL_AVAILABILITY(shadermodel, 6.2) +const inline __detail::enable_if_t<__detail::is_same<int16_t, T>::value || + __detail::is_same<uint16_t, T>::value, + uint> firstbithigh(T X) { + return __detail::firstbithigh_impl<uint, T, 16>(X); +} + +template <typename T, int N> +_HLSL_AVAILABILITY(shadermodel, 6.2) +const + inline __detail::enable_if_t<__detail::is_same<int16_t, T>::value || + __detail::is_same<uint16_t, T>::value, + vector<uint, N>> firstbithigh(vector<T, N> X) { + return __detail::firstbithigh_impl<vector<uint, N>, vector<T, N>, 16>(X); +} + +#endif + +template <typename T> +const inline __detail::enable_if_t< + __detail::is_same<int, T>::value || __detail::is_same<uint, T>::value, uint> +firstbithigh(T X) { + return __detail::firstbithigh_impl<uint, T, 32>(X); +} + +template <typename T, int N> +const inline __detail::enable_if_t<__detail::is_same<int, T>::value || + __detail::is_same<uint, T>::value, + vector<uint, N>> +firstbithigh(vector<T, N> X) { + return __detail::firstbithigh_impl<vector<uint, N>, vector<T, N>, 32>(X); +} + +template <typename T> +const inline __detail::enable_if_t<__detail::is_same<int64_t, T>::value || + __detail::is_same<uint64_t, T>::value, + uint> +firstbithigh(T X) { + return __detail::firstbithigh_impl<uint, T, 64>(X); +} + +template <typename T, int N> +const inline __detail::enable_if_t<__detail::is_same<int64_t, T>::value || + __detail::is_same<uint64_t, T>::value, + vector<uint, N>> +firstbithigh(vector<T, N> X) { + return __detail::firstbithigh_impl<vector<uint, N>, vector<T, N>, 64>(X); +} + +//===----------------------------------------------------------------------===// // fmod builtins //===----------------------------------------------------------------------===// diff --git a/clang/lib/Headers/llvm_libc_wrappers/stdlib.h b/clang/lib/Headers/llvm_libc_wrappers/stdlib.h index 1da22abd0..d79e7fa 100644 --- a/clang/lib/Headers/llvm_libc_wrappers/stdlib.h +++ b/clang/lib/Headers/llvm_libc_wrappers/stdlib.h @@ -34,13 +34,13 @@ _Static_assert(__builtin_offsetof(div_t, quot) == 0, "ABI mismatch!"); _Static_assert(__builtin_offsetof(ldiv_t, quot) == 0, "ABI mismatch!"); _Static_assert(__builtin_offsetof(lldiv_t, quot) == 0, "ABI mismatch!"); -#if defined(__GLIBC__) && __cplusplus >= 201703L +#if defined(__GLIBC__) && __cplusplus >= 201103L #define at_quick_exit atexit #endif #include <llvm-libc-decls/stdlib.h> -#if defined(__GLIBC__) && __cplusplus >= 201703L +#if defined(__GLIBC__) && __cplusplus >= 201103L #undef at_quick_exit #endif diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index cde354c..7633806 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -394,36 +394,48 @@ Interpreter::outOfProcessJITBuilder(JITConfig Config) { llvm::Expected<std::string> Interpreter::getOrcRuntimePath(const driver::ToolChain &TC) { - std::optional<std::string> CompilerRTPath = TC.getCompilerRTPath(); - std::optional<std::string> ResourceDir = TC.getRuntimePath(); + const std::array<const char *, 3> OrcRTLibNames = { + "liborc_rt.a", "liborc_rt_osx.a", "liborc_rt-x86_64.a"}; + + auto findInDir = [&](llvm::StringRef Base) -> std::optional<std::string> { + for (const char *LibName : OrcRTLibNames) { + llvm::SmallString<256> CandidatePath(Base); + llvm::sys::path::append(CandidatePath, LibName); + if (llvm::sys::fs::exists(CandidatePath)) + return std::string(CandidatePath.str()); + } + return std::nullopt; + }; + + std::string SearchedPaths; - if (!CompilerRTPath) { + if (std::optional<std::string> CompilerRTPath = TC.getCompilerRTPath()) { + if (auto Found = findInDir(*CompilerRTPath)) + return *Found; + SearchedPaths += *CompilerRTPath; + } else { return llvm::make_error<llvm::StringError>("CompilerRT path not found", std::error_code()); } - const std::array<const char *, 3> OrcRTLibNames = { - "liborc_rt.a", "liborc_rt_osx.a", "liborc_rt-x86_64.a"}; - - for (const char *LibName : OrcRTLibNames) { - llvm::SmallString<256> CandidatePath((*CompilerRTPath).c_str()); - llvm::sys::path::append(CandidatePath, LibName); - - if (llvm::sys::fs::exists(CandidatePath)) { - return CandidatePath.str().str(); - } + if (std::optional<std::string> ResourceDir = TC.getRuntimePath()) { + if (auto Found = findInDir(*ResourceDir)) + return *Found; + if (!SearchedPaths.empty()) + SearchedPaths += "; "; + SearchedPaths += *ResourceDir; + } else { + return llvm::make_error<llvm::StringError>("ResourceDir path not found", + std::error_code()); } return llvm::make_error<llvm::StringError>( - llvm::Twine("OrcRuntime library not found in: ") + (*CompilerRTPath), + llvm::Twine("OrcRuntime library not found in: ") + SearchedPaths, std::error_code()); } llvm::Expected<std::unique_ptr<Interpreter>> Interpreter::create(std::unique_ptr<CompilerInstance> CI, JITConfig Config) { - llvm::Error Err = llvm::Error::success(); - - std::unique_ptr<llvm::orc::LLJITBuilder> JB; if (Config.IsOutOfProcess) { const TargetInfo &TI = CI->getTarget(); @@ -453,6 +465,9 @@ Interpreter::create(std::unique_ptr<CompilerInstance> CI, JITConfig Config) { } } + llvm::Error Err = llvm::Error::success(); + std::unique_ptr<llvm::orc::LLJITBuilder> JB; + auto Interp = std::unique_ptr<Interpreter>(new Interpreter( std::move(CI), Err, std::move(JB), /*Consumer=*/nullptr, Config)); if (auto E = std::move(Err)) diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 74f87a8..7a5d28c 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -772,9 +772,11 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, // Produce a diagnostic if we're not tentatively parsing; otherwise track // that our parse has failed. - auto Invalid = [&](llvm::function_ref<void()> Action) { + auto Result = [&](llvm::function_ref<void()> Action, + LambdaIntroducerTentativeParse State = + LambdaIntroducerTentativeParse::Invalid) { if (Tentative) { - *Tentative = LambdaIntroducerTentativeParse::Invalid; + *Tentative = State; return false; } Action(); @@ -824,7 +826,7 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, break; } - return Invalid([&] { + return Result([&] { Diag(Tok.getLocation(), diag::err_expected_comma_or_rsquare); }); } @@ -861,7 +863,7 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, ConsumeToken(); Kind = LCK_StarThis; } else { - return Invalid([&] { + return Result([&] { Diag(Tok.getLocation(), diag::err_expected_star_this_capture); }); } @@ -875,8 +877,9 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, // or the start of a capture (in the "&" case) with the rest of the // capture missing. Both are an error but a misplaced capture-default // is more likely if we don't already have a capture default. - return Invalid( - [&] { Diag(Tok.getLocation(), diag::err_capture_default_first); }); + return Result( + [&] { Diag(Tok.getLocation(), diag::err_capture_default_first); }, + LambdaIntroducerTentativeParse::Incomplete); } else { TryConsumeToken(tok::ellipsis, EllipsisLocs[0]); @@ -899,14 +902,13 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, Id = Tok.getIdentifierInfo(); Loc = ConsumeToken(); } else if (Tok.is(tok::kw_this)) { - return Invalid([&] { + return Result([&] { // FIXME: Suggest a fixit here. Diag(Tok.getLocation(), diag::err_this_captured_by_reference); }); } else { - return Invalid([&] { - Diag(Tok.getLocation(), diag::err_expected_capture); - }); + return Result( + [&] { Diag(Tok.getLocation(), diag::err_expected_capture); }); } TryConsumeToken(tok::ellipsis, EllipsisLocs[2]); diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 31bc941..334438e 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -3178,6 +3178,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_align: case OMPC_message: case OMPC_ompx_dyn_cgroup_mem: + case OMPC_dyn_groupprivate: // OpenMP [2.5, Restrictions] // At most one num_threads clause can appear on the directive. // OpenMP [2.8.1, simd construct, Restrictions] @@ -3216,7 +3217,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, PP.LookAhead(/*N=*/0).isNot(tok::l_paren)) Clause = ParseOpenMPClause(CKind, WrongDirective); else if (CKind == OMPC_grainsize || CKind == OMPC_num_tasks || - CKind == OMPC_num_threads) + CKind == OMPC_num_threads || CKind == OMPC_dyn_groupprivate) Clause = ParseOpenMPSingleExprWithArgClause(DKind, CKind, WrongDirective); else Clause = ParseOpenMPSingleExprClause(CKind, WrongDirective); @@ -4009,6 +4010,83 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind, Arg.push_back(OMPC_GRAINSIZE_unknown); KLoc.emplace_back(); } + } else if (Kind == OMPC_dyn_groupprivate) { + enum { SimpleModifier, ComplexModifier, NumberOfModifiers }; + Arg.resize(NumberOfModifiers); + KLoc.resize(NumberOfModifiers); + Arg[SimpleModifier] = OMPC_DYN_GROUPPRIVATE_unknown; + Arg[ComplexModifier] = OMPC_DYN_GROUPPRIVATE_FALLBACK_unknown; + + auto ConsumeModifier = [&]() { + unsigned Type = NumberOfModifiers; + unsigned Modifier; + SourceLocation Loc; + if (!Tok.isAnnotation() && PP.getSpelling(Tok) == "fallback" && + NextToken().is(tok::l_paren)) { + ConsumeToken(); + BalancedDelimiterTracker ParenT(*this, tok::l_paren, tok::r_paren); + ParenT.consumeOpen(); + + Modifier = getOpenMPSimpleClauseType( + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()); + if (Modifier <= OMPC_DYN_GROUPPRIVATE_FALLBACK_unknown || + Modifier >= OMPC_DYN_GROUPPRIVATE_FALLBACK_last) { + Diag(Tok.getLocation(), diag::err_expected) + << "'abort', 'null' or 'default_mem' in fallback modifier"; + SkipUntil(tok::r_paren); + return std::make_tuple(Type, Modifier, Loc); + } + Type = ComplexModifier; + Loc = Tok.getLocation(); + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && + Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + ParenT.consumeClose(); + } else { + Modifier = getOpenMPSimpleClauseType( + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()); + if (Modifier < OMPC_DYN_GROUPPRIVATE_unknown) { + Type = SimpleModifier; + Loc = Tok.getLocation(); + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && + Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + } + } + return std::make_tuple(Type, Modifier, Loc); + }; + + auto SaveModifier = [&](unsigned Type, unsigned Modifier, + SourceLocation Loc) { + assert(Type < NumberOfModifiers && "Unexpected modifier type"); + if (!KLoc[Type].isValid()) { + Arg[Type] = Modifier; + KLoc[Type] = Loc; + } else { + Diag(Loc, diag::err_omp_incompatible_dyn_groupprivate_modifier) + << getOpenMPSimpleClauseTypeName(OMPC_dyn_groupprivate, Modifier) + << getOpenMPSimpleClauseTypeName(OMPC_dyn_groupprivate, Arg[Type]); + } + }; + + // Parse 'modifier' + auto [Type1, Mod1, Loc1] = ConsumeModifier(); + if (Type1 < NumberOfModifiers) { + SaveModifier(Type1, Mod1, Loc1); + if (Tok.is(tok::comma)) { + // Parse ',' 'modifier' + ConsumeAnyToken(); + auto [Type2, Mod2, Loc2] = ConsumeModifier(); + if (Type2 < NumberOfModifiers) + SaveModifier(Type2, Mod2, Loc2); + } + // Parse ':' + if (Tok.is(tok::colon)) + ConsumeAnyToken(); + else + Diag(Tok, diag::warn_pragma_expected_colon) + << "dyn_groupprivate modifier"; + } } else if (Kind == OMPC_num_tasks) { // Parse optional <num_tasks modifier> ':' OpenMPNumTasksClauseModifier Modifier = @@ -4083,11 +4161,11 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind, } } - bool NeedAnExpression = (Kind == OMPC_schedule && DelimLoc.isValid()) || - (Kind == OMPC_dist_schedule && DelimLoc.isValid()) || - Kind == OMPC_if || Kind == OMPC_device || - Kind == OMPC_grainsize || Kind == OMPC_num_tasks || - Kind == OMPC_num_threads; + bool NeedAnExpression = + (Kind == OMPC_schedule && DelimLoc.isValid()) || + (Kind == OMPC_dist_schedule && DelimLoc.isValid()) || Kind == OMPC_if || + Kind == OMPC_device || Kind == OMPC_grainsize || Kind == OMPC_num_tasks || + Kind == OMPC_num_threads || Kind == OMPC_dyn_groupprivate; if (NeedAnExpression) { SourceLocation ELoc = Tok.getLocation(); ExprResult LHS( diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index fb45db1..7e73d89c 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1079,16 +1079,10 @@ bool Parser::ConsumeNullStmt(StmtVector &Stmts) { StmtResult Parser::handleExprStmt(ExprResult E, ParsedStmtContext StmtCtx) { bool IsStmtExprResult = false; if ((StmtCtx & ParsedStmtContext::InStmtExpr) != ParsedStmtContext()) { - // For GCC compatibility we skip past NullStmts. - unsigned LookAhead = 0; - while (GetLookAheadToken(LookAhead).is(tok::semi)) { - ++LookAhead; - } - // Then look to see if the next two tokens close the statement expression; - // if so, this expression statement is the last statement in a statement - // expression. - IsStmtExprResult = GetLookAheadToken(LookAhead).is(tok::r_brace) && - GetLookAheadToken(LookAhead + 1).is(tok::r_paren); + // Look ahead to see if the next two tokens close the statement expression; + // if so, this expression statement is the last statement in a + // statment expression. + IsStmtExprResult = Tok.is(tok::r_brace) && NextToken().is(tok::r_paren); } if (IsStmtExprResult) diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 23bf7f2..46addea 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -321,9 +321,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, static_cast<unsigned>(ComparisonCategoryType::Last) + 1), StdSourceLocationImplDecl(nullptr), CXXTypeInfoDecl(nullptr), GlobalNewDeleteDeclared(false), DisableTypoCorrection(false), - TyposCorrected(0), IsBuildingRecoveryCallExpr(false), NumSFINAEErrors(0), - AccessCheckingSFINAE(false), CurrentInstantiationScope(nullptr), - InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0), + TyposCorrected(0), IsBuildingRecoveryCallExpr(false), + CurrentInstantiationScope(nullptr), NonInstantiationEntries(0), ArgPackSubstIndex(std::nullopt), SatisfactionCache(Context) { assert(pp.TUKind == TUKind); TUScope = nullptr; @@ -670,7 +669,9 @@ void Sema::addExternalSource(IntrusiveRefCntPtr<ExternalSemaSource> E) { void Sema::PrintStats() const { llvm::errs() << "\n*** Semantic Analysis Stats:\n"; - llvm::errs() << NumSFINAEErrors << " SFINAE diagnostics trapped.\n"; + if (SFINAETrap *Trap = getSFINAEContext()) + llvm::errs() << int(Trap->hasErrorOccurred()) + << " SFINAE diagnostics trapped.\n"; BumpAlloc.PrintStats(); AnalysisWarnings.PrintStats(); @@ -1681,7 +1682,8 @@ void Sema::EmitDiagnostic(unsigned DiagID, const DiagnosticBuilder &DB) { // issue I am not seeing yet), then there should at least be a clarifying // comment somewhere. Diagnostic DiagInfo(&Diags, DB); - if (std::optional<TemplateDeductionInfo *> Info = isSFINAEContext()) { + if (SFINAETrap *Trap = getSFINAEContext()) { + sema::TemplateDeductionInfo *Info = Trap->getDeductionInfo(); switch (DiagnosticIDs::getDiagnosticSFINAEResponse(DiagInfo.getID())) { case DiagnosticIDs::SFINAE_Report: // We'll report the diagnostic below. @@ -1690,37 +1692,37 @@ void Sema::EmitDiagnostic(unsigned DiagID, const DiagnosticBuilder &DB) { case DiagnosticIDs::SFINAE_SubstitutionFailure: // Count this failure so that we know that template argument deduction // has failed. - ++NumSFINAEErrors; + Trap->setErrorOccurred(); // Make a copy of this suppressed diagnostic and store it with the // template-deduction information. - if (*Info && !(*Info)->hasSFINAEDiagnostic()) { - (*Info)->addSFINAEDiagnostic(DiagInfo.getLocation(), - PartialDiagnostic(DiagInfo, Context.getDiagAllocator())); - } + if (Info && !Info->hasSFINAEDiagnostic()) + Info->addSFINAEDiagnostic( + DiagInfo.getLocation(), + PartialDiagnostic(DiagInfo, Context.getDiagAllocator())); Diags.setLastDiagnosticIgnored(true); return; case DiagnosticIDs::SFINAE_AccessControl: { // Per C++ Core Issue 1170, access control is part of SFINAE. - // Additionally, the AccessCheckingSFINAE flag can be used to temporarily + // Additionally, the WithAccessChecking flag can be used to temporarily // make access control a part of SFINAE for the purposes of checking // type traits. - if (!AccessCheckingSFINAE && !getLangOpts().CPlusPlus11) + if (!Trap->withAccessChecking() && !getLangOpts().CPlusPlus11) break; SourceLocation Loc = DiagInfo.getLocation(); // Suppress this diagnostic. - ++NumSFINAEErrors; + Trap->setErrorOccurred(); // Make a copy of this suppressed diagnostic and store it with the // template-deduction information. - if (*Info && !(*Info)->hasSFINAEDiagnostic()) { - (*Info)->addSFINAEDiagnostic(DiagInfo.getLocation(), - PartialDiagnostic(DiagInfo, Context.getDiagAllocator())); - } + if (Info && !Info->hasSFINAEDiagnostic()) + Info->addSFINAEDiagnostic( + DiagInfo.getLocation(), + PartialDiagnostic(DiagInfo, Context.getDiagAllocator())); Diags.setLastDiagnosticIgnored(true); @@ -1740,13 +1742,13 @@ void Sema::EmitDiagnostic(unsigned DiagID, const DiagnosticBuilder &DB) { return; // Make a copy of this suppressed diagnostic and store it with the // template-deduction information; - if (*Info) { - (*Info)->addSuppressedDiagnostic( + if (Info) { + Info->addSuppressedDiagnostic( DiagInfo.getLocation(), PartialDiagnostic(DiagInfo, Context.getDiagAllocator())); if (!Diags.getDiagnosticIDs()->isNote(DiagID)) PrintContextStack([Info](SourceLocation Loc, PartialDiagnostic PD) { - (*Info)->addSuppressedDiagnostic(Loc, std::move(PD)); + Info->addSuppressedDiagnostic(Loc, std::move(PD)); }); } diff --git a/clang/lib/Sema/SemaAMDGPU.cpp b/clang/lib/Sema/SemaAMDGPU.cpp index 139c4ab..cece220 100644 --- a/clang/lib/Sema/SemaAMDGPU.cpp +++ b/clang/lib/Sema/SemaAMDGPU.cpp @@ -558,6 +558,8 @@ AMDGPUMaxNumWorkGroupsAttr *SemaAMDGPU::CreateAMDGPUMaxNumWorkGroupsAttr( const AttributeCommonInfo &CI, Expr *XExpr, Expr *YExpr, Expr *ZExpr) { ASTContext &Context = getASTContext(); AMDGPUMaxNumWorkGroupsAttr TmpAttr(Context, CI, XExpr, YExpr, ZExpr); + assert(!SemaRef.isSFINAEContext() && + "Can't produce SFINAE diagnostic pointing to temporary attribute"); if (checkAMDGPUMaxNumWorkGroupsArguments(SemaRef, XExpr, YExpr, ZExpr, TmpAttr)) diff --git a/clang/lib/Sema/SemaBoundsSafety.cpp b/clang/lib/Sema/SemaBoundsSafety.cpp index 39ab136..de9adf8 100644 --- a/clang/lib/Sema/SemaBoundsSafety.cpp +++ b/clang/lib/Sema/SemaBoundsSafety.cpp @@ -132,9 +132,23 @@ bool Sema::CheckCountedByAttrOnField(FieldDecl *FD, Expr *E, bool CountInBytes, // `BoundsSafetyCheckUseOfCountAttrPtr` // // * When the pointee type is always an incomplete type (e.g. - // `void`) the attribute is disallowed by this method because we know the - // type can never be completed so there's no reason to allow it. - InvalidTypeKind = CountedByInvalidPointeeTypeKind::INCOMPLETE; + // `void` in strict C mode) the attribute is disallowed by this method + // because we know the type can never be completed so there's no reason + // to allow it. + // + // Exception: void has an implicit size of 1 byte for pointer arithmetic + // (following GNU convention). Therefore, counted_by on void* is allowed + // and behaves equivalently to sized_by (treating the count as bytes). + bool IsVoidPtr = PointeeTy->isVoidType(); + if (IsVoidPtr) { + // Emit a warning that this is a GNU extension. + Diag(FD->getBeginLoc(), diag::ext_gnu_counted_by_void_ptr) << Kind; + Diag(FD->getBeginLoc(), diag::note_gnu_counted_by_void_ptr_use_sized_by) + << Kind; + assert(InvalidTypeKind == CountedByInvalidPointeeTypeKind::VALID); + } else { + InvalidTypeKind = CountedByInvalidPointeeTypeKind::INCOMPLETE; + } } else if (PointeeTy->isSizelessType()) { InvalidTypeKind = CountedByInvalidPointeeTypeKind::SIZELESS; } else if (PointeeTy->isFunctionType()) { @@ -272,6 +286,9 @@ GetCountedByAttrOnIncompletePointee(QualType Ty, NamedDecl **ND) { if (!PointeeTy->isIncompleteType(ND)) return {}; + if (PointeeTy->isVoidType()) + return {}; + return {CATy, PointeeTy}; } diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index fb4d0b45..883e341 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -526,12 +526,12 @@ ExprResult ConstraintSatisfactionChecker::EvaluateAtomicConstraint( S, AtomicExpr->getBeginLoc(), Sema::InstantiatingTemplate::ConstraintSubstitution{}, // FIXME: improve const-correctness of InstantiatingTemplate - const_cast<NamedDecl *>(Template), Info, AtomicExpr->getSourceRange()); + const_cast<NamedDecl *>(Template), AtomicExpr->getSourceRange()); if (Inst.isInvalid()) return ExprError(); // We do not want error diagnostics escaping here. - Sema::SFINAETrap Trap(S); + Sema::SFINAETrap Trap(S, Info); SubstitutedExpression = S.SubstConstraintExpr(const_cast<Expr *>(AtomicExpr), MLTAL); @@ -599,16 +599,15 @@ ConstraintSatisfactionChecker::SubstitutionInTemplateArguments( return MultiLevelTemplateArgumentList(); TemplateDeductionInfo Info(Constraint.getBeginLoc()); + Sema::SFINAETrap Trap(S, Info); Sema::InstantiatingTemplate Inst( S, Constraint.getBeginLoc(), Sema::InstantiatingTemplate::ConstraintSubstitution{}, // FIXME: improve const-correctness of InstantiatingTemplate - const_cast<NamedDecl *>(Template), Info, Constraint.getSourceRange()); + const_cast<NamedDecl *>(Template), Constraint.getSourceRange()); if (Inst.isInvalid()) return std::nullopt; - Sema::SFINAETrap Trap(S); - TemplateArgumentListInfo SubstArgs; Sema::ArgPackSubstIndexRAII SubstIndex( S, Constraint.getPackSubstitutionIndex() @@ -778,9 +777,6 @@ ConstraintSatisfactionChecker::EvaluateFoldExpandedConstraintSize( const FoldExpandedConstraint &FE, const MultiLevelTemplateArgumentList &MLTAL) { - // We should ignore errors in the presence of packs of different size. - Sema::SFINAETrap Trap(S); - Expr *Pattern = const_cast<Expr *>(FE.getPattern()); SmallVector<UnexpandedParameterPack, 2> Unexpanded; @@ -792,18 +788,12 @@ ConstraintSatisfactionChecker::EvaluateFoldExpandedConstraintSize( if (S.CheckParameterPacksForExpansion( Pattern->getExprLoc(), Pattern->getSourceRange(), Unexpanded, MLTAL, /*FailOnPackProducingTemplates=*/false, Expand, RetainExpansion, - NumExpansions) || + NumExpansions, /*Diagnose=*/false) || !Expand || RetainExpansion) return std::nullopt; - if (NumExpansions && S.getLangOpts().BracketDepth < *NumExpansions) { - S.Diag(Pattern->getExprLoc(), - clang::diag::err_fold_expression_limit_exceeded) - << *NumExpansions << S.getLangOpts().BracketDepth - << Pattern->getSourceRange(); - S.Diag(Pattern->getExprLoc(), diag::note_bracket_depth); + if (NumExpansions && S.getLangOpts().BracketDepth < *NumExpansions) return std::nullopt; - } return NumExpansions; } @@ -921,7 +911,6 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow( return ExprError(); } - Sema::SFINAETrap Trap(S); Sema::ArgPackSubstIndexRAII SubstIndex( S, Constraint.getPackSubstitutionIndex() ? Constraint.getPackSubstitutionIndex() @@ -930,9 +919,10 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow( const ASTTemplateArgumentListInfo *Ori = ConceptId->getTemplateArgsAsWritten(); TemplateDeductionInfo Info(TemplateNameLoc); - Sema::InstantiatingTemplate _( + Sema::SFINAETrap Trap(S, Info); + Sema::InstantiatingTemplate _2( S, TemplateNameLoc, Sema::InstantiatingTemplate::ConstraintSubstitution{}, - const_cast<NamedDecl *>(Template), Info, Constraint.getSourceRange()); + const_cast<NamedDecl *>(Template), Constraint.getSourceRange()); TemplateArgumentListInfo OutArgs(Ori->LAngleLoc, Ori->RAngleLoc); if (S.SubstTemplateArguments(Ori->arguments(), *SubstitutedArgs, OutArgs) || @@ -1142,13 +1132,21 @@ static bool CheckConstraintSatisfaction( if (TemplateArgsLists.getNumLevels() != 0) Args = TemplateArgsLists.getInnermost(); - std::optional<Sema::InstantiatingTemplate> SynthesisContext; - if (!TopLevelConceptId) { - SynthesisContext.emplace(S, TemplateIDRange.getBegin(), - Sema::InstantiatingTemplate::ConstraintsCheck{}, - const_cast<NamedDecl *>(Template), Args, + struct SynthesisContextPair { + Sema::InstantiatingTemplate Inst; + Sema::NonSFINAEContext NSC; + SynthesisContextPair(Sema &S, NamedDecl *Template, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange InstantiationRange) + : Inst(S, InstantiationRange.getBegin(), + Sema::InstantiatingTemplate::ConstraintsCheck{}, Template, + TemplateArgs, InstantiationRange), + NSC(S) {} + }; + std::optional<SynthesisContextPair> SynthesisContext; + if (!TopLevelConceptId) + SynthesisContext.emplace(S, const_cast<NamedDecl *>(Template), Args, TemplateIDRange); - } const NormalizedConstraint *C = S.getNormalizedAssociatedConstraints(Template, AssociatedConstraints); @@ -1478,8 +1476,7 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction( if (MLTAL.getNumSubstitutedLevels() == 0) return ConstrExpr; - Sema::SFINAETrap SFINAE(S); - + Sema::NonSFINAEContext _(S); Sema::InstantiatingTemplate Inst( S, DeclInfo.getLocation(), Sema::InstantiatingTemplate::ConstraintNormalization{}, @@ -1554,7 +1551,7 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction( Sema::ReuseLambdaContextDecl); ExprResult SubstConstr = S.SubstConstraintExprWithoutSatisfaction( const_cast<clang::Expr *>(ConstrExpr), MLTAL); - if (SFINAE.hasErrorOccurred() || !SubstConstr.isUsable()) + if (!SubstConstr.isUsable()) return nullptr; return SubstConstr.get(); } @@ -2104,6 +2101,7 @@ bool SubstituteParameterMappings::substitute( InstLocBegin = SR.getBegin(); InstLocEnd = SR.getEnd(); } + Sema::NonSFINAEContext _(SemaRef); Sema::InstantiatingTemplate Inst( SemaRef, InstLocBegin, Sema::InstantiatingTemplate::ParameterMappingSubstitution{}, @@ -2171,6 +2169,7 @@ bool SubstituteParameterMappings::substitute(ConceptIdConstraint &CC) { InstLocBegin = SR.getBegin(); InstLocEnd = SR.getEnd(); } + Sema::NonSFINAEContext _(SemaRef); // This is useful for name lookup across modules; see Sema::getLookupModules. Sema::InstantiatingTemplate Inst( SemaRef, InstLocBegin, @@ -2311,6 +2310,7 @@ NormalizedConstraint *NormalizedConstraint::fromConstraintExpr( } else if (auto *CSE = dyn_cast<const ConceptSpecializationExpr>(E)) { NormalizedConstraint *SubNF; { + Sema::NonSFINAEContext _(S); Sema::InstantiatingTemplate Inst( S, CSE->getExprLoc(), Sema::InstantiatingTemplate::ConstraintNormalization{}, @@ -2546,8 +2546,6 @@ bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic( }; { - // The subsumption checks might cause diagnostics - SFINAETrap Trap(*this); auto *Normalized1 = getNormalizedAssociatedConstraints(D1, AC1); if (!Normalized1) return false; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index fc3aabf..086dd8b 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8492,12 +8492,11 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl, DeclContext *NewDC = D->getDeclContext(); if (FieldDecl *FD = dyn_cast<FieldDecl>(ShadowedDecl)) { - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewDC)) { - // Fields are not shadowed by variables in C++ static methods. - if (MD->isStatic()) - return; - - if (!MD->getParent()->isLambda() && MD->isExplicitObjectMemberFunction()) + if (const auto *MD = + dyn_cast<CXXMethodDecl>(getFunctionLevelDeclContext())) { + // Fields aren't shadowed in C++ static members or in member functions + // with an explicit object parameter. + if (MD->isStatic() || MD->isExplicitObjectMemberFunction()) return; } // Fields shadowed by constructor parameters are a special case. Usually diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index a50c276..2159a0d 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -12653,10 +12653,10 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // This is a gcc extension compatibility comparison. // In a SFINAE context, we treat this as a hard error to maintain // conformance with the C++ standard. - diagnoseFunctionPointerToVoidComparison( - *this, Loc, LHS, RHS, /*isError*/ (bool)isSFINAEContext()); + bool IsError = isSFINAEContext(); + diagnoseFunctionPointerToVoidComparison(*this, Loc, LHS, RHS, IsError); - if (isSFINAEContext()) + if (IsError) return QualType(); RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); @@ -14598,11 +14598,11 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { unsigned AddressOfError = AO_No_Error; if (lval == Expr::LV_ClassTemporary || lval == Expr::LV_ArrayTemporary) { - bool sfinae = (bool)isSFINAEContext(); - Diag(OpLoc, isSFINAEContext() ? diag::err_typecheck_addrof_temporary - : diag::ext_typecheck_addrof_temporary) - << op->getType() << op->getSourceRange(); - if (sfinae) + bool IsError = isSFINAEContext(); + Diag(OpLoc, IsError ? diag::err_typecheck_addrof_temporary + : diag::ext_typecheck_addrof_temporary) + << op->getType() << op->getSourceRange(); + if (IsError) return QualType(); // Materialize the temporary as an lvalue so that we can take its address. OrigOp = op = @@ -16185,9 +16185,7 @@ ExprResult Sema::BuildStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, QualType Ty = Context.VoidTy; bool StmtExprMayBindToTemp = false; if (!Compound->body_empty()) { - // For GCC compatibility we get the last Stmt excluding trailing NullStmts. - if (const auto *LastStmt = - dyn_cast<ValueStmt>(Compound->getStmtExprResult())) { + if (const auto *LastStmt = dyn_cast<ValueStmt>(Compound->body_back())) { if (const Expr *Value = LastStmt->getExprStmt()) { StmtExprMayBindToTemp = true; Ty = Value->getType(); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 256f952..465dab2 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -16532,6 +16532,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, case OMPC_holds: Res = ActOnOpenMPHoldsClause(Expr, StartLoc, LParenLoc, EndLoc); break; + case OMPC_dyn_groupprivate: case OMPC_grainsize: case OMPC_num_tasks: case OMPC_num_threads: @@ -16658,6 +16659,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_num_teams: case OMPC_thread_limit: case OMPC_ompx_dyn_cgroup_mem: + case OMPC_dyn_groupprivate: + // TODO: This may need to consider teams too. if (Leafs[0] == OMPD_target) return OMPD_target; break; @@ -17705,7 +17708,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprWithArgClause( SourceLocation EndLoc) { OMPClause *Res = nullptr; switch (Kind) { - case OMPC_schedule: + case OMPC_schedule: { enum { Modifier1, Modifier2, ScheduleKind, NumberOfElements }; assert(Argument.size() == NumberOfElements && ArgumentLoc.size() == NumberOfElements); @@ -17716,6 +17719,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprWithArgClause( StartLoc, LParenLoc, ArgumentLoc[Modifier1], ArgumentLoc[Modifier2], ArgumentLoc[ScheduleKind], DelimLoc, EndLoc); break; + } case OMPC_if: assert(Argument.size() == 1 && ArgumentLoc.size() == 1); Res = ActOnOpenMPIfClause(static_cast<OpenMPDirectiveKind>(Argument.back()), @@ -17771,6 +17775,20 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprWithArgClause( static_cast<OpenMPNumTasksClauseModifier>(Argument.back()), Expr, StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc); break; + case OMPC_dyn_groupprivate: { + enum { Modifier1, Modifier2, NumberOfElements }; + assert(Argument.size() == NumberOfElements && + ArgumentLoc.size() == NumberOfElements && + "Modifiers for dyn_groupprivate clause and their locations are " + "expected."); + Res = ActOnOpenMPDynGroupprivateClause( + static_cast<OpenMPDynGroupprivateClauseModifier>(Argument[Modifier1]), + static_cast<OpenMPDynGroupprivateClauseFallbackModifier>( + Argument[Modifier2]), + Expr, StartLoc, LParenLoc, ArgumentLoc[Modifier1], + ArgumentLoc[Modifier2], EndLoc); + break; + } case OMPC_num_threads: assert(Argument.size() == 1 && ArgumentLoc.size() == 1 && "Modifier for num_threads clause and its location are expected."); @@ -18127,6 +18145,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_affinity: case OMPC_when: case OMPC_ompx_dyn_cgroup_mem: + case OMPC_dyn_groupprivate: default: llvm_unreachable("Clause is not allowed."); } @@ -25246,6 +25265,49 @@ OMPClause *SemaOpenMP::ActOnOpenMPXDynCGroupMemClause(Expr *Size, ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc); } +OMPClause *SemaOpenMP::ActOnOpenMPDynGroupprivateClause( + OpenMPDynGroupprivateClauseModifier M1, + OpenMPDynGroupprivateClauseFallbackModifier M2, Expr *Size, + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation M1Loc, + SourceLocation M2Loc, SourceLocation EndLoc) { + + if ((M1Loc.isValid() && M1 == OMPC_DYN_GROUPPRIVATE_unknown) || + (M2Loc.isValid() && M2 == OMPC_DYN_GROUPPRIVATE_FALLBACK_unknown)) { + std::string Values = getListOfPossibleValues( + OMPC_dyn_groupprivate, /*First=*/0, OMPC_DYN_GROUPPRIVATE_unknown); + Diag((M1Loc.isValid() && M1 == OMPC_DYN_GROUPPRIVATE_unknown) ? M1Loc + : M2Loc, + diag::err_omp_unexpected_clause_value) + << Values << getOpenMPClauseName(OMPC_dyn_groupprivate); + return nullptr; + } + + Expr *ValExpr = Size; + Stmt *HelperValStmt = nullptr; + + // OpenMP [2.5, Restrictions] + // The dyn_groupprivate expression must evaluate to a positive integer + // value. + if (!isNonNegativeIntegerValue(ValExpr, SemaRef, OMPC_dyn_groupprivate, + /*StrictlyPositive=*/false)) + return nullptr; + + OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); + OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause( + DKind, OMPC_dyn_groupprivate, getLangOpts().OpenMP); + if (CaptureRegion != OMPD_unknown && + !SemaRef.CurContext->isDependentContext()) { + ValExpr = SemaRef.MakeFullExpr(ValExpr).get(); + llvm::MapVector<const Expr *, DeclRefExpr *> Captures; + ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get(); + HelperValStmt = buildPreInits(getASTContext(), Captures); + } + + return new (getASTContext()) OMPDynGroupprivateClause( + StartLoc, LParenLoc, EndLoc, ValExpr, HelperValStmt, CaptureRegion, M1, + M1Loc, M2, M2Loc); +} + OMPClause *SemaOpenMP::ActOnOpenMPDoacrossClause( OpenMPDoacrossClauseModifier DepType, SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList, SourceLocation StartLoc, diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 983a784..4a9e1bc 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3846,13 +3846,14 @@ QualType Sema::CheckTemplateIdType(ElaboratedTypeKeyword Keyword, // within enable_if in a SFINAE context, dig out the specific // enable_if condition that failed and present that instead. if (isEnableIfAliasTemplate(AliasTemplate)) { - if (auto DeductionInfo = isSFINAEContext()) { - if (*DeductionInfo && - (*DeductionInfo)->hasSFINAEDiagnostic() && - (*DeductionInfo)->peekSFINAEDiagnostic().second.getDiagID() == - diag::err_typename_nested_not_found_enable_if && - TemplateArgs[0].getArgument().getKind() - == TemplateArgument::Expression) { + if (SFINAETrap *Trap = getSFINAEContext(); + TemplateDeductionInfo *DeductionInfo = + Trap ? Trap->getDeductionInfo() : nullptr) { + if (DeductionInfo->hasSFINAEDiagnostic() && + DeductionInfo->peekSFINAEDiagnostic().second.getDiagID() == + diag::err_typename_nested_not_found_enable_if && + TemplateArgs[0].getArgument().getKind() == + TemplateArgument::Expression) { Expr *FailedCond; std::string FailedDescription; std::tie(FailedCond, FailedDescription) = @@ -3861,15 +3862,14 @@ QualType Sema::CheckTemplateIdType(ElaboratedTypeKeyword Keyword, // Remove the old SFINAE diagnostic. PartialDiagnosticAt OldDiag = {SourceLocation(), PartialDiagnostic::NullDiagnostic()}; - (*DeductionInfo)->takeSFINAEDiagnostic(OldDiag); + DeductionInfo->takeSFINAEDiagnostic(OldDiag); // Add a new SFINAE diagnostic specifying which condition // failed. - (*DeductionInfo)->addSFINAEDiagnostic( - OldDiag.first, - PDiag(diag::err_typename_nested_not_found_requirement) - << FailedDescription - << FailedCond->getSourceRange()); + DeductionInfo->addSFINAEDiagnostic( + OldDiag.first, + PDiag(diag::err_typename_nested_not_found_requirement) + << FailedDescription << FailedCond->getSourceRange()); } } } @@ -3955,6 +3955,7 @@ QualType Sema::CheckTemplateIdType(ElaboratedTypeKeyword Keyword, if (Decl->getSpecializationKind() == TSK_Undeclared && ClassTemplate->getTemplatedDecl()->hasAttrs()) { + NonSFINAEContext _(*this); InstantiatingTemplate Inst(*this, TemplateLoc, Decl); if (!Inst.isInvalid()) { MultiLevelTemplateArgumentList TemplateArgLists(Template, @@ -5565,12 +5566,11 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc, auto checkExpr = [&](Expr *E) -> Expr * { TemplateArgument SugaredResult, CanonicalResult; - unsigned CurSFINAEErrors = NumSFINAEErrors; ExprResult Res = CheckTemplateArgument( NTTP, NTTPType, E, SugaredResult, CanonicalResult, /*StrictCheck=*/CTAI.MatchingTTP || CTAI.PartialOrdering, CTAK); // If the current template argument causes an error, give up now. - if (Res.isInvalid() || CurSFINAEErrors < NumSFINAEErrors) + if (Res.isInvalid()) return nullptr; CTAI.SugaredConverted.push_back(SugaredResult); CTAI.CanonicalConverted.push_back(CanonicalResult); diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 6964242..a287319 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3239,10 +3239,6 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction( ArrayRef<TemplateArgumentLoc> Ps, ArrayRef<TemplateArgument> As, SmallVectorImpl<DeducedTemplateArgument> &Deduced, TemplateDeductionInfo &Info, bool CopyDeducedArgs) { - // Unevaluated SFINAE context. - EnterExpressionEvaluationContext Unevaluated( - S, Sema::ExpressionEvaluationContext::Unevaluated); - Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(Entity)); // C++ [temp.deduct.type]p2: @@ -3380,10 +3376,6 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction( Sema &S, TemplateDecl *TD, SmallVectorImpl<DeducedTemplateArgument> &Deduced, TemplateDeductionInfo &Info) { - // Unevaluated SFINAE context. - EnterExpressionEvaluationContext Unevaluated( - S, Sema::ExpressionEvaluationContext::Unevaluated); - Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(TD)); // C++ [temp.deduct.type]p2: @@ -3423,7 +3415,7 @@ DeduceTemplateArguments(Sema &S, T *Partial, // Unevaluated SFINAE context. EnterExpressionEvaluationContext Unevaluated( S, Sema::ExpressionEvaluationContext::Unevaluated); - Sema::SFINAETrap Trap(S); + Sema::SFINAETrap Trap(S, Info); // This deduction has no relation to any outer instantiation we might be // performing. @@ -3441,8 +3433,7 @@ DeduceTemplateArguments(Sema &S, T *Partial, return Result; SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end()); - Sema::InstantiatingTemplate Inst(S, Info.getLocation(), Partial, DeducedArgs, - Info); + Sema::InstantiatingTemplate Inst(S, Info.getLocation(), Partial, DeducedArgs); if (Inst.isInvalid()) return TemplateDeductionResult::InstantiationDepth; @@ -3497,7 +3488,7 @@ Sema::DeduceTemplateArgumentsFromType(TemplateDecl *TD, QualType FromType, // Unevaluated SFINAE context. EnterExpressionEvaluationContext Unevaluated( *this, Sema::ExpressionEvaluationContext::Unevaluated); - SFINAETrap Trap(*this); + SFINAETrap Trap(*this, Info); // This deduction has no relation to any outer instantiation we might be // performing. @@ -3514,7 +3505,7 @@ Sema::DeduceTemplateArgumentsFromType(TemplateDecl *TD, QualType FromType, } SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end()); - InstantiatingTemplate Inst(*this, Info.getLocation(), TD, DeducedArgs, Info); + InstantiatingTemplate Inst(*this, Info.getLocation(), TD, DeducedArgs); if (Inst.isInvalid()) return TemplateDeductionResult::InstantiationDepth; @@ -3558,6 +3549,9 @@ TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( SmallVectorImpl<DeducedTemplateArgument> &Deduced, SmallVectorImpl<QualType> &ParamTypes, QualType *FunctionType, TemplateDeductionInfo &Info) { + assert(isSFINAEContext()); + assert(isUnevaluatedContext()); + FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); @@ -3573,11 +3567,6 @@ TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( return TemplateDeductionResult::Success; } - // Unevaluated SFINAE context. - EnterExpressionEvaluationContext Unevaluated( - *this, Sema::ExpressionEvaluationContext::Unevaluated); - SFINAETrap Trap(*this); - // C++ [temp.arg.explicit]p3: // Template arguments that are present shall be specified in the // declaration order of their corresponding template-parameters. The @@ -3590,7 +3579,7 @@ TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( SmallVector<TemplateArgument, 4> DeducedArgs; InstantiatingTemplate Inst( *this, Info.getLocation(), FunctionTemplate, DeducedArgs, - CodeSynthesisContext::ExplicitTemplateArgumentSubstitution, Info); + CodeSynthesisContext::ExplicitTemplateArgumentSubstitution); if (Inst.isInvalid()) return TemplateDeductionResult::InstantiationDepth; @@ -3598,8 +3587,7 @@ TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( if (CheckTemplateArgumentList(FunctionTemplate, SourceLocation(), ExplicitTemplateArgs, /*DefaultArgs=*/{}, /*PartialTemplateArgs=*/true, CTAI, - /*UpdateArgsWithConversions=*/false) || - Trap.hasErrorOccurred()) { + /*UpdateArgsWithConversions=*/false)) { unsigned Index = CTAI.SugaredConverted.size(); if (Index >= TemplateParams->size()) return TemplateDeductionResult::SubstitutionFailure; @@ -3688,7 +3676,7 @@ TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( ResultType = SubstType(Proto->getReturnType(), MLTAL, Function->getTypeSpecStartLoc(), Function->getDeclName()); - if (ResultType.isNull() || Trap.hasErrorOccurred()) + if (ResultType.isNull()) return TemplateDeductionResult::SubstitutionFailure; // CUDA: Kernel function must have 'void' return type. if (getLangOpts().CUDA) @@ -3714,7 +3702,7 @@ TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( Function->getLocation(), Function->getDeclName(), EPI); - if (FunctionType->isNull() || Trap.hasErrorOccurred()) + if (FunctionType->isNull()) return TemplateDeductionResult::SubstitutionFailure; } @@ -3912,12 +3900,15 @@ static TemplateDeductionResult instantiateExplicitSpecifierDeferred( if (!ExplicitExpr->isValueDependent()) return TemplateDeductionResult::Success; + // By this point, FinishTemplateArgumentDeduction will have been reverted back + // to a regular non-SFINAE template instantiation context, so setup a new + // SFINAE context. Sema::InstantiatingTemplate Inst( S, Info.getLocation(), FunctionTemplate, DeducedArgs, - Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info); + Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution); if (Inst.isInvalid()) return TemplateDeductionResult::InstantiationDepth; - Sema::SFINAETrap Trap(S); + Sema::SFINAETrap Trap(S, Info); const ExplicitSpecifier InstantiatedES = S.instantiateExplicitSpecifier(SubstArgs, ES); if (InstantiatedES.isInvalid() || Trap.hasErrorOccurred()) { @@ -3937,17 +3928,12 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( bool PartialOverloading, bool PartialOrdering, bool ForOverloadSetAddressResolution, llvm::function_ref<bool(bool)> CheckNonDependent) { - // Unevaluated SFINAE context. - EnterExpressionEvaluationContext Unevaluated( - *this, Sema::ExpressionEvaluationContext::Unevaluated); - SFINAETrap Trap(*this); - // Enter a new template instantiation context while we instantiate the // actual function declaration. SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end()); InstantiatingTemplate Inst( *this, Info.getLocation(), FunctionTemplate, DeducedArgs, - CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info); + CodeSynthesisContext::DeducedTemplateArgumentSubstitution); if (Inst.isInvalid()) return TemplateDeductionResult::InstantiationDepth; @@ -4030,18 +4016,9 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( // If the template argument list is owned by the function template // specialization, release it. if (Specialization->getTemplateSpecializationArgs() == - CanonicalDeducedArgumentList && - !Trap.hasErrorOccurred()) + CanonicalDeducedArgumentList) Info.takeCanonical(); - // There may have been an error that did not prevent us from constructing a - // declaration. Mark the declaration invalid and return with a substitution - // failure. - if (Trap.hasErrorOccurred()) { - Specialization->setInvalidDecl(true); - return TemplateDeductionResult::SubstitutionFailure; - } - // C++2a [temp.deduct]p5 // [...] When all template arguments have been deduced [...] all uses of // template parameters [...] are replaced with the corresponding deduced @@ -4553,6 +4530,10 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( return TemplateDeductionResult::TooManyArguments; } + EnterExpressionEvaluationContext Unevaluated( + *this, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap Trap(*this, Info); + // The types of the parameters from which we will perform template argument // deduction. LocalInstantiationScope InstScope(*this); @@ -4570,6 +4551,8 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( }); if (Result != TemplateDeductionResult::Success) return Result; + if (Trap.hasErrorOccurred()) + return TemplateDeductionResult::SubstitutionFailure; NumExplicitlySpecified = Deduced.size(); } else { @@ -4743,6 +4726,11 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( OnlyInitializeNonUserDefinedConversions); }); }); + if (Trap.hasErrorOccurred()) { + if (Specialization) + Specialization->setInvalidDecl(true); + return TemplateDeductionResult::SubstitutionFailure; + } return Result; } @@ -4795,6 +4783,14 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( = FunctionTemplate->getTemplateParameters(); QualType FunctionType = Function->getType(); + bool PotentiallyEvaluated = + currentEvaluationContext().isPotentiallyEvaluated(); + + // Unevaluated SFINAE context. + EnterExpressionEvaluationContext Unevaluated( + *this, Sema::ExpressionEvaluationContext::Unevaluated); + SFINAETrap Trap(*this, Info); + // Substitute any explicit template arguments. LocalInstantiationScope InstScope(*this); SmallVector<DeducedTemplateArgument, 4> Deduced; @@ -4809,6 +4805,8 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( }); if (Result != TemplateDeductionResult::Success) return Result; + if (Trap.hasErrorOccurred()) + return TemplateDeductionResult::SubstitutionFailure; NumExplicitlySpecified = Deduced.size(); } @@ -4820,11 +4818,6 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, FunctionType, /*AdjustExceptionSpec*/false); - // Unevaluated SFINAE context. - std::optional<EnterExpressionEvaluationContext> Unevaluated( - std::in_place, *this, Sema::ExpressionEvaluationContext::Unevaluated); - SFINAETrap Trap(*this); - Deduced.resize(TemplateParams->size()); // If the function has a deduced return type, substitute it for a dependent @@ -4865,14 +4858,12 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( DeduceReturnType(Specialization, Info.getLocation(), false)) return TemplateDeductionResult::MiscellaneousDeductionFailure; - Unevaluated = std::nullopt; // [C++26][expr.const]/p17 // An expression or conversion is immediate-escalating if it is not initially // in an immediate function context and it is [...] // a potentially-evaluated id-expression that denotes an immediate function. if (IsAddressOfFunction && getLangOpts().CPlusPlus20 && - Specialization->isImmediateEscalating() && - currentEvaluationContext().isPotentiallyEvaluated() && + Specialization->isImmediateEscalating() && PotentiallyEvaluated && CheckIfFunctionSpecializationIsImmediate(Specialization, Info.getLocation())) return TemplateDeductionResult::MiscellaneousDeductionFailure; @@ -4975,7 +4966,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( // Unevaluated SFINAE context. EnterExpressionEvaluationContext Unevaluated( *this, Sema::ExpressionEvaluationContext::Unevaluated); - SFINAETrap Trap(*this); + SFINAETrap Trap(*this, Info); // C++ [temp.deduct.conv]p1: // Template argument deduction is done by comparing the return @@ -5614,10 +5605,6 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction( Sema &S, FunctionTemplateDecl *FTD, SmallVectorImpl<DeducedTemplateArgument> &Deduced, TemplateDeductionInfo &Info, T &&CheckDeductionConsistency) { - EnterExpressionEvaluationContext Unevaluated( - S, Sema::ExpressionEvaluationContext::Unevaluated); - Sema::SFINAETrap Trap(S); - Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(FTD)); // C++26 [temp.deduct.type]p2: @@ -5645,13 +5632,7 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction( // and verify that the instantiated argument is both valid // and equivalent to the parameter. LocalInstantiationScope InstScope(S); - - if (auto TDR = CheckDeductionConsistency(S, FTD, CTAI.SugaredConverted); - TDR != TemplateDeductionResult::Success) - return TDR; - - return Trap.hasErrorOccurred() ? TemplateDeductionResult::SubstitutionFailure - : TemplateDeductionResult::Success; + return CheckDeductionConsistency(S, FTD, CTAI.SugaredConverted); } /// Determine whether the function template \p FT1 is at least as @@ -5717,9 +5698,12 @@ static bool isAtLeastAsSpecializedAs( } SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end()); + EnterExpressionEvaluationContext Unevaluated( + S, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap Trap(S, Info); Sema::InstantiatingTemplate Inst( S, Info.getLocation(), FT2, DeducedArgs, - Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info); + Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution); if (Inst.isInvalid()) return false; @@ -5765,7 +5749,7 @@ static bool isAtLeastAsSpecializedAs( }); }) == TemplateDeductionResult::Success; }); - if (!AtLeastAsSpecialized) + if (!AtLeastAsSpecialized || Trap.hasErrorOccurred()) return false; // C++0x [temp.deduct.partial]p11: @@ -6241,10 +6225,11 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, /*HasDeducedAnyParam=*/nullptr) != TemplateDeductionResult::Success) return false; - SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), - Deduced.end()); - Sema::InstantiatingTemplate Inst(S, Info.getLocation(), P2, DeducedArgs, - Info); + SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end()); + EnterExpressionEvaluationContext Unevaluated( + S, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap Trap(S, Info); + Sema::InstantiatingTemplate Inst(S, Info.getLocation(), P2, DeducedArgs); if (Inst.isInvalid()) return false; @@ -6252,8 +6237,6 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, Ps = cast<TemplateSpecializationType>(T2)->template_arguments(), As = cast<TemplateSpecializationType>(T1)->template_arguments(); - Sema::SFINAETrap Trap(S); - TemplateDeductionResult Result; S.runWithSufficientStackSpace(Info.getLocation(), [&] { Result = ::FinishTemplateArgumentDeduction( @@ -6261,14 +6244,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, /*IsPartialOrdering=*/true, Ps, As, Deduced, Info, /*CopyDeducedArgs=*/false); }); - - if (Result != TemplateDeductionResult::Success) - return false; - - if (Trap.hasErrorOccurred()) - return false; - - return true; + return Result == TemplateDeductionResult::Success && !Trap.hasErrorOccurred(); } namespace { diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 40811d4..bfb1066 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -1025,6 +1025,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate, FunctionTemplateDecl *F, SourceLocation Loc) { LocalInstantiationScope Scope(SemaRef); + Sema::NonSFINAEContext _1(SemaRef); Sema::InstantiatingTemplate BuildingDeductionGuides( SemaRef, AliasTemplate->getLocation(), F, Sema::InstantiatingTemplate::BuildingDeductionGuidesTag{}); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 5fceacd..35205f4 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -606,8 +606,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, CodeSynthesisContext::SynthesisKind Kind, SourceLocation PointOfInstantiation, SourceRange InstantiationRange, - Decl *Entity, NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs, - sema::TemplateDeductionInfo *DeductionInfo) + Decl *Entity, NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs) : SemaRef(SemaRef) { // Don't allow further instantiation if a fatal error and an uncompilable // error have occurred. Any diagnostics we might have raised will not be @@ -625,7 +624,6 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( Inst.Template = Template; Inst.TemplateArgs = TemplateArgs.data(); Inst.NumTemplateArgs = TemplateArgs.size(); - Inst.DeductionInfo = DeductionInfo; Inst.InstantiationRange = InstantiationRange; Inst.InConstraintSubstitution = Inst.Kind == CodeSynthesisContext::ConstraintSubstitution; @@ -671,48 +669,40 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionTemplateDecl *FunctionTemplate, ArrayRef<TemplateArgument> TemplateArgs, - CodeSynthesisContext::SynthesisKind Kind, - sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) + CodeSynthesisContext::SynthesisKind Kind, SourceRange InstantiationRange) : InstantiatingTemplate(SemaRef, Kind, PointOfInstantiation, InstantiationRange, FunctionTemplate, nullptr, - TemplateArgs, &DeductionInfo) { + TemplateArgs) { assert(Kind == CodeSynthesisContext::ExplicitTemplateArgumentSubstitution || Kind == CodeSynthesisContext::DeducedTemplateArgumentSubstitution || Kind == CodeSynthesisContext::BuildingDeductionGuides); } Sema::InstantiatingTemplate::InstantiatingTemplate( - Sema &SemaRef, SourceLocation PointOfInstantiation, - TemplateDecl *Template, - ArrayRef<TemplateArgument> TemplateArgs, - sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) + Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template, + ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange) : InstantiatingTemplate( - SemaRef, - CodeSynthesisContext::DeducedTemplateArgumentSubstitution, + SemaRef, CodeSynthesisContext::DeducedTemplateArgumentSubstitution, PointOfInstantiation, InstantiationRange, Template, nullptr, - TemplateArgs, &DeductionInfo) {} + TemplateArgs) {} Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, ClassTemplatePartialSpecializationDecl *PartialSpec, - ArrayRef<TemplateArgument> TemplateArgs, - sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) + ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange) : InstantiatingTemplate( - SemaRef, - CodeSynthesisContext::DeducedTemplateArgumentSubstitution, + SemaRef, CodeSynthesisContext::DeducedTemplateArgumentSubstitution, PointOfInstantiation, InstantiationRange, PartialSpec, nullptr, - TemplateArgs, &DeductionInfo) {} + TemplateArgs) {} Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, VarTemplatePartialSpecializationDecl *PartialSpec, - ArrayRef<TemplateArgument> TemplateArgs, - sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) + ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange) : InstantiatingTemplate( - SemaRef, - CodeSynthesisContext::DeducedTemplateArgumentSubstitution, + SemaRef, CodeSynthesisContext::DeducedTemplateArgumentSubstitution, PointOfInstantiation, InstantiationRange, PartialSpec, nullptr, - TemplateArgs, &DeductionInfo) {} + TemplateArgs) {} Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, ParmVarDecl *Param, @@ -763,12 +753,11 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, - concepts::Requirement *Req, sema::TemplateDeductionInfo &DeductionInfo, - SourceRange InstantiationRange) + concepts::Requirement *Req, SourceRange InstantiationRange) : InstantiatingTemplate( SemaRef, CodeSynthesisContext::RequirementInstantiation, PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr, - /*Template=*/nullptr, /*TemplateArgs=*/{}, &DeductionInfo) {} + /*Template=*/nullptr, /*TemplateArgs=*/{}) {} Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -781,11 +770,11 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, const RequiresExpr *RE, - sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) + SourceRange InstantiationRange) : InstantiatingTemplate( SemaRef, CodeSynthesisContext::RequirementParameterInstantiation, PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr, - /*Template=*/nullptr, /*TemplateArgs=*/{}, &DeductionInfo) {} + /*Template=*/nullptr, /*TemplateArgs=*/{}) {} Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -797,13 +786,11 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( TemplateArgs) {} Sema::InstantiatingTemplate::InstantiatingTemplate( - Sema &SemaRef, SourceLocation PointOfInstantiation, - ConstraintSubstitution, NamedDecl *Template, - sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) + Sema &SemaRef, SourceLocation PointOfInstantiation, ConstraintSubstitution, + NamedDecl *Template, SourceRange InstantiationRange) : InstantiatingTemplate( SemaRef, CodeSynthesisContext::ConstraintSubstitution, - PointOfInstantiation, InstantiationRange, Template, nullptr, - {}, &DeductionInfo) {} + PointOfInstantiation, InstantiationRange, Template, nullptr, {}) {} Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -835,9 +822,6 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( ArgLoc, InstantiationRange, PArg) {} bool Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) { - Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext; - InNonInstantiationSFINAEContext = false; - if (!Ctx.isInstantiationRecord()) { ++NonInstantiationEntries; } else { @@ -871,8 +855,6 @@ void Sema::popCodeSynthesisContext() { --NonInstantiationEntries; } - InNonInstantiationSFINAEContext = Active.SavedInNonInstantiationSFINAEContext; - // Name lookup no longer looks in this template's defining module. assert(CodeSynthesisContexts.size() >= CodeSynthesisContextLookupModules.size() && @@ -1282,93 +1264,6 @@ void Sema::PrintInstantiationStack(InstantiationContextDiagFuncRef DiagFunc) { } } -std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { - if (InNonInstantiationSFINAEContext) - return std::optional<TemplateDeductionInfo *>(nullptr); - - for (SmallVectorImpl<CodeSynthesisContext>::const_reverse_iterator - Active = CodeSynthesisContexts.rbegin(), - ActiveEnd = CodeSynthesisContexts.rend(); - Active != ActiveEnd; - ++Active) - { - switch (Active->Kind) { - case CodeSynthesisContext::TypeAliasTemplateInstantiation: - // An instantiation of an alias template may or may not be a SFINAE - // context, depending on what else is on the stack. - if (isa<TypeAliasTemplateDecl>(Active->Entity)) - break; - [[fallthrough]]; - case CodeSynthesisContext::TemplateInstantiation: - case CodeSynthesisContext::DefaultFunctionArgumentInstantiation: - case CodeSynthesisContext::ExceptionSpecInstantiation: - case CodeSynthesisContext::ConstraintsCheck: - case CodeSynthesisContext::ParameterMappingSubstitution: - case CodeSynthesisContext::ConstraintNormalization: - case CodeSynthesisContext::NestedRequirementConstraintsCheck: - // This is a template instantiation, so there is no SFINAE. - return std::nullopt; - case CodeSynthesisContext::LambdaExpressionSubstitution: - // [temp.deduct]p9 - // A lambda-expression appearing in a function type or a template - // parameter is not considered part of the immediate context for the - // purposes of template argument deduction. - // CWG2672: A lambda-expression body is never in the immediate context. - return std::nullopt; - - case CodeSynthesisContext::DefaultTemplateArgumentInstantiation: - case CodeSynthesisContext::PriorTemplateArgumentSubstitution: - case CodeSynthesisContext::DefaultTemplateArgumentChecking: - case CodeSynthesisContext::RewritingOperatorAsSpaceship: - case CodeSynthesisContext::PartialOrderingTTP: - // A default template argument instantiation and substitution into - // template parameters with arguments for prior parameters may or may - // not be a SFINAE context; look further up the stack. - break; - - case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution: - case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: - // We're either substituting explicitly-specified template arguments, - // deduced template arguments. SFINAE applies unless we are in a lambda - // body, see [temp.deduct]p9. - case CodeSynthesisContext::ConstraintSubstitution: - case CodeSynthesisContext::RequirementInstantiation: - case CodeSynthesisContext::RequirementParameterInstantiation: - // SFINAE always applies in a constraint expression or a requirement - // in a requires expression. - assert(Active->DeductionInfo && "Missing deduction info pointer"); - return Active->DeductionInfo; - - case CodeSynthesisContext::DeclaringSpecialMember: - case CodeSynthesisContext::DeclaringImplicitEqualityComparison: - case CodeSynthesisContext::DefiningSynthesizedFunction: - case CodeSynthesisContext::InitializingStructuredBinding: - case CodeSynthesisContext::MarkingClassDllexported: - case CodeSynthesisContext::BuildingBuiltinDumpStructCall: - case CodeSynthesisContext::BuildingDeductionGuides: - // This happens in a context unrelated to template instantiation, so - // there is no SFINAE. - return std::nullopt; - - case CodeSynthesisContext::ExceptionSpecEvaluation: - // FIXME: This should not be treated as a SFINAE context, because - // we will cache an incorrect exception specification. However, clang - // bootstrap relies this! See PR31692. - break; - - case CodeSynthesisContext::Memoization: - break; - } - - // The inner context was transparent for SFINAE. If it occurred within a - // non-instantiation SFINAE context, then SFINAE applies. - if (Active->SavedInNonInstantiationSFINAEContext) - return std::optional<TemplateDeductionInfo *>(nullptr); - } - - return std::nullopt; -} - //===----------------------------------------------------------------------===/ // Template Instantiation for Types //===----------------------------------------------------------------------===/ @@ -2674,10 +2569,9 @@ ExprResult TemplateInstantiator::TransformRequiresTypeParams( Sema::ExtParameterInfoBuilder &PInfos) { TemplateDeductionInfo Info(KWLoc); - Sema::InstantiatingTemplate TypeInst(SemaRef, KWLoc, - RE, Info, + Sema::InstantiatingTemplate TypeInst(SemaRef, KWLoc, RE, SourceRange{KWLoc, RBraceLoc}); - Sema::SFINAETrap Trap(SemaRef); + Sema::SFINAETrap Trap(SemaRef, Info); unsigned ErrorIdx; if (getDerived().TransformFunctionTypeParams( @@ -2709,10 +2603,10 @@ TemplateInstantiator::TransformTypeRequirement(concepts::TypeRequirement *Req) { return Req; } - Sema::SFINAETrap Trap(SemaRef); TemplateDeductionInfo Info(Req->getType()->getTypeLoc().getBeginLoc()); - Sema::InstantiatingTemplate TypeInst(SemaRef, - Req->getType()->getTypeLoc().getBeginLoc(), Req, Info, + Sema::SFINAETrap Trap(SemaRef, Info); + Sema::InstantiatingTemplate TypeInst( + SemaRef, Req->getType()->getTypeLoc().getBeginLoc(), Req, Req->getType()->getTypeLoc().getSourceRange()); if (TypeInst.isInvalid()) return nullptr; @@ -2730,8 +2624,6 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) { if (!Req->isDependent() && !AlwaysRebuild()) return Req; - Sema::SFINAETrap Trap(SemaRef); - llvm::PointerUnion<Expr *, concepts::Requirement::SubstitutionDiagnostic *> TransExpr; if (Req->isExprSubstitutionFailure()) @@ -2739,7 +2631,8 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) { else { Expr *E = Req->getExpr(); TemplateDeductionInfo Info(E->getBeginLoc()); - Sema::InstantiatingTemplate ExprInst(SemaRef, E->getBeginLoc(), Req, Info, + Sema::SFINAETrap Trap(SemaRef, Info); + Sema::InstantiatingTemplate ExprInst(SemaRef, E->getBeginLoc(), Req, E->getSourceRange()); if (ExprInst.isInvalid()) return nullptr; @@ -2765,8 +2658,9 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) { TemplateParameterList *OrigTPL = RetReq.getTypeConstraintTemplateParameterList(); TemplateDeductionInfo Info(OrigTPL->getTemplateLoc()); - Sema::InstantiatingTemplate TPLInst(SemaRef, OrigTPL->getTemplateLoc(), - Req, Info, OrigTPL->getSourceRange()); + Sema::SFINAETrap Trap(SemaRef, Info); + Sema::InstantiatingTemplate TPLInst(SemaRef, OrigTPL->getTemplateLoc(), Req, + OrigTPL->getSourceRange()); if (TPLInst.isInvalid()) return nullptr; TemplateParameterList *TPL = TransformTemplateParameterList(OrigTPL); @@ -2830,11 +2724,9 @@ TemplateInstantiator::TransformNestedRequirement( bool Success; Expr *NewConstraint; - TemplateDeductionInfo Info(Constraint->getBeginLoc()); { EnterExpressionEvaluationContext ContextRAII( SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); - Sema::InstantiatingTemplate ConstrInst( SemaRef, Constraint->getBeginLoc(), Req, Sema::InstantiatingTemplate::ConstraintsCheck(), @@ -2843,16 +2735,10 @@ TemplateInstantiator::TransformNestedRequirement( if (ConstrInst.isInvalid()) return nullptr; - Sema::SFINAETrap Trap(SemaRef); - Success = !SemaRef.CheckConstraintSatisfaction( Req, AssociatedConstraint(Constraint, SemaRef.ArgPackSubstIndex), TemplateArgs, Constraint->getSourceRange(), Satisfaction, /*TopLevelConceptId=*/nullptr, &NewConstraint); - - assert((!Success || !Trap.hasErrorOccurred()) && - "Substitution failures must be handled " - "by CheckConstraintSatisfaction."); } if (!Success || Satisfaction.HasSubstitutionFailure()) @@ -3306,7 +3192,7 @@ bool Sema::SubstDefaultArgument( EnterExpressionEvaluationContext EvalContext( *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); - + NonSFINAEContext _(*this); InstantiatingTemplate Inst(*this, Loc, Param, TemplateArgs.getInnermost()); if (Inst.isInvalid()) return true; @@ -3594,6 +3480,7 @@ bool Sema::InstantiateClassImpl( Spec->setPointOfInstantiation(PointOfInstantiation); } + NonSFINAEContext _(*this); InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst.isInvalid()) return true; @@ -3828,6 +3715,7 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation, MSInfo->setPointOfInstantiation(PointOfInstantiation); } + NonSFINAEContext _(*this); InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst.isInvalid()) return true; @@ -3892,6 +3780,7 @@ bool Sema::InstantiateInClassInitializer( return true; } + NonSFINAEContext _(*this); InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst.isInvalid()) return true; @@ -3975,6 +3864,7 @@ static ActionResult<CXXRecordDecl *> getPatternForClassTemplateSpecialization( Sema &S, SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, TemplateSpecializationKind TSK, bool PrimaryStrictPackMatch) { + std::optional<Sema::NonSFINAEContext> NSC(S); Sema::InstantiatingTemplate Inst(S, PointOfInstantiation, ClassTemplateSpec); if (Inst.isInvalid()) return {/*Invalid=*/true}; @@ -4076,6 +3966,7 @@ static ActionResult<CXXRecordDecl *> getPatternForClassTemplateSpecialization( if (Ambiguous) { // Partial ordering did not produce a clear winner. Complain. Inst.Clear(); + NSC.reset(); S.Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous) << ClassTemplateSpec; @@ -4507,6 +4398,7 @@ ExprResult Sema::SubstConceptTemplateArguments( TemplateArgumentListInfo SubstArgs(ArgsAsWritten->getLAngleLoc(), ArgsAsWritten->getRAngleLoc()); + NonSFINAEContext _(*this); Sema::InstantiatingTemplate Inst( *this, ArgsAsWritten->arguments().front().getSourceRange().getBegin(), Sema::InstantiatingTemplate::ConstraintNormalization{}, diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 681bfe0..4d58f00 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -5316,6 +5316,7 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, return; } + NonSFINAEContext _(*this); InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl, InstantiatingTemplate::ExceptionSpecification()); if (Inst.isInvalid()) { @@ -5383,6 +5384,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution || ActiveInst.Kind == ActiveInstType::DeducedTemplateArgumentSubstitution) { if (isa<FunctionTemplateDecl>(ActiveInst.Entity)) { + SemaRef.CurrentSFINAEContext = nullptr; atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, ActiveInst); ActiveInst.Kind = ActiveInstType::TemplateInstantiation; ActiveInst.Entity = New; @@ -5493,8 +5495,7 @@ FunctionDecl *Sema::InstantiateFunctionDeclaration( SourceLocation Loc, CodeSynthesisContext::SynthesisKind CSC) { FunctionDecl *FD = FTD->getTemplatedDecl(); - sema::TemplateDeductionInfo Info(Loc); - InstantiatingTemplate Inst(*this, Loc, FTD, Args->asArray(), CSC, Info); + InstantiatingTemplate Inst(*this, Loc, FTD, Args->asArray(), CSC); if (Inst.isInvalid()) return nullptr; @@ -5684,6 +5685,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, } } + NonSFINAEContext _(*this); InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); if (Inst.isInvalid()) return; @@ -5974,6 +5976,7 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation( if (FromVar->isInvalidDecl()) return nullptr; + NonSFINAEContext _(*this); InstantiatingTemplate Inst(*this, PointOfInstantiation, FromVar); if (Inst.isInvalid()) return nullptr; @@ -6281,6 +6284,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, !Var->hasInit()) { // FIXME: Factor out the duplicated instantiation context setup/tear down // code here. + NonSFINAEContext _(*this); InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); if (Inst.isInvalid()) return; @@ -6385,6 +6389,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, return; } + NonSFINAEContext _(*this); InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); if (Inst.isInvalid()) return; diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 0f72d6a..5b1aad3 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -844,7 +844,7 @@ bool Sema::CheckParameterPacksForExpansion( ArrayRef<UnexpandedParameterPack> Unexpanded, const MultiLevelTemplateArgumentList &TemplateArgs, bool FailOnPackProducingTemplates, bool &ShouldExpand, - bool &RetainExpansion, UnsignedOrNone &NumExpansions) { + bool &RetainExpansion, UnsignedOrNone &NumExpansions, bool Diagnose) { ShouldExpand = true; RetainExpansion = false; IdentifierLoc FirstPack; @@ -874,6 +874,9 @@ bool Sema::CheckParameterPacksForExpansion( if (!FailOnPackProducingTemplates) continue; + if (!Diagnose) + return true; + // It is not yet supported in certain contexts. return Diag(PatternRange.getBegin().isValid() ? PatternRange.getBegin() : EllipsisLoc, @@ -1015,7 +1018,9 @@ bool Sema::CheckParameterPacksForExpansion( // C++0x [temp.variadic]p5: // All of the parameter packs expanded by a pack expansion shall have // the same number of arguments specified. - if (HaveFirstPack) + if (!Diagnose) + ; + else if (HaveFirstPack) Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict) << FirstPack.getIdentifierInfo() << Name << *NumExpansions << (LeastNewPackSize != NewPackSize) << LeastNewPackSize @@ -1041,6 +1046,8 @@ bool Sema::CheckParameterPacksForExpansion( if (NumExpansions && *NumExpansions < *NumPartialExpansions) { NamedDecl *PartialPack = CurrentInstantiationScope->getPartiallySubstitutedPack(); + if (!Diagnose) + return true; Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_partial) << PartialPack << *NumPartialExpansions << *NumExpansions << SourceRange(PartiallySubstitutedPackLoc); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index dffd7c1..c249148 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2463,6 +2463,19 @@ public: LParenLoc, EndLoc); } + /// Build a new OpenMP 'dyn_groupprivate' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPDynGroupprivateClause( + OpenMPDynGroupprivateClauseModifier M1, + OpenMPDynGroupprivateClauseFallbackModifier M2, Expr *Size, + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation M1Loc, + SourceLocation M2Loc, SourceLocation EndLoc) { + return getSema().OpenMP().ActOnOpenMPDynGroupprivateClause( + M1, M2, Size, StartLoc, LParenLoc, M1Loc, M2Loc, EndLoc); + } + /// Build a new OpenMP 'ompx_attribute' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. @@ -8076,14 +8089,13 @@ TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S, getSema().resetFPOptions( S->getStoredFPFeatures().applyOverrides(getSema().getLangOpts())); - const Stmt *ExprResult = S->getStmtExprResult(); bool SubStmtInvalid = false; bool SubStmtChanged = false; SmallVector<Stmt*, 8> Statements; for (auto *B : S->body()) { StmtResult Result = getDerived().TransformStmt( - B, IsStmtExpr && B == ExprResult ? StmtDiscardKind::StmtExprResult - : StmtDiscardKind::Discarded); + B, IsStmtExpr && B == S->body_back() ? StmtDiscardKind::StmtExprResult + : StmtDiscardKind::Discarded); if (Result.isInvalid()) { // Immediately fail if this was a DeclStmt, since it's very @@ -11727,6 +11739,19 @@ OMPClause *TreeTransform<Derived>::TransformOMPXDynCGroupMemClause( } template <typename Derived> +OMPClause *TreeTransform<Derived>::TransformOMPDynGroupprivateClause( + OMPDynGroupprivateClause *C) { + ExprResult Size = getDerived().TransformExpr(C->getSize()); + if (Size.isInvalid()) + return nullptr; + return getDerived().RebuildOMPDynGroupprivateClause( + C->getDynGroupprivateModifier(), C->getDynGroupprivateFallbackModifier(), + Size.get(), C->getBeginLoc(), C->getLParenLoc(), + C->getDynGroupprivateModifierLoc(), + C->getDynGroupprivateFallbackModifierLoc(), C->getEndLoc()); +} + +template <typename Derived> OMPClause * TreeTransform<Derived>::TransformOMPDoacrossClause(OMPDoacrossClause *C) { llvm::SmallVector<Expr *, 16> Vars; @@ -15824,16 +15849,20 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { Sema::ExpressionEvaluationContext::PotentiallyEvaluated, E->getCallOperator()); - Sema::CodeSynthesisContext C; - C.Kind = clang::Sema::CodeSynthesisContext::LambdaExpressionSubstitution; - C.PointOfInstantiation = E->getBody()->getBeginLoc(); - getSema().pushCodeSynthesisContext(C); + StmtResult Body; + { + Sema::NonSFINAEContext _(getSema()); + Sema::CodeSynthesisContext C; + C.Kind = clang::Sema::CodeSynthesisContext::LambdaExpressionSubstitution; + C.PointOfInstantiation = E->getBody()->getBeginLoc(); + getSema().pushCodeSynthesisContext(C); - // Instantiate the body of the lambda expression. - StmtResult Body = - Invalid ? StmtError() : getDerived().TransformLambdaBody(E, E->getBody()); + // Instantiate the body of the lambda expression. + Body = Invalid ? StmtError() + : getDerived().TransformLambdaBody(E, E->getBody()); - getSema().popCodeSynthesisContext(); + getSema().popCodeSynthesisContext(); + } // ActOnLambda* will pop the function scope for us. FuncScopeCleanup.disable(); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index d552821..a04041c 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -11544,6 +11544,9 @@ OMPClause *OMPClauseReader::readClause() { case llvm::omp::OMPC_ompx_dyn_cgroup_mem: C = new (Context) OMPXDynCGroupMemClause(); break; + case llvm::omp::OMPC_dyn_groupprivate: + C = new (Context) OMPDynGroupprivateClause(); + break; case llvm::omp::OMPC_doacross: { unsigned NumVars = Record.readInt(); unsigned NumLoops = Record.readInt(); @@ -12736,6 +12739,19 @@ void OMPClauseReader::VisitOMPXDynCGroupMemClause(OMPXDynCGroupMemClause *C) { C->setLParenLoc(Record.readSourceLocation()); } +void OMPClauseReader::VisitOMPDynGroupprivateClause( + OMPDynGroupprivateClause *C) { + VisitOMPClauseWithPreInit(C); + C->setDynGroupprivateModifier( + Record.readEnum<OpenMPDynGroupprivateClauseModifier>()); + C->setDynGroupprivateFallbackModifier( + Record.readEnum<OpenMPDynGroupprivateClauseFallbackModifier>()); + C->setSize(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); + C->setDynGroupprivateModifierLoc(Record.readSourceLocation()); + C->setDynGroupprivateFallbackModifierLoc(Record.readSourceLocation()); +} + void OMPClauseReader::VisitOMPDoacrossClause(OMPDoacrossClause *C) { C->setLParenLoc(Record.readSourceLocation()); C->setDependenceType( diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index b1fd151..821e7df 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -8651,6 +8651,17 @@ void OMPClauseWriter::VisitOMPXDynCGroupMemClause(OMPXDynCGroupMemClause *C) { Record.AddSourceLocation(C->getLParenLoc()); } +void OMPClauseWriter::VisitOMPDynGroupprivateClause( + OMPDynGroupprivateClause *C) { + VisitOMPClauseWithPreInit(C); + Record.push_back(C->getDynGroupprivateModifier()); + Record.push_back(C->getDynGroupprivateFallbackModifier()); + Record.AddStmt(C->getSize()); + Record.AddSourceLocation(C->getLParenLoc()); + Record.AddSourceLocation(C->getDynGroupprivateModifierLoc()); + Record.AddSourceLocation(C->getDynGroupprivateFallbackModifierLoc()); +} + void OMPClauseWriter::VisitOMPDoacrossClause(OMPDoacrossClause *C) { Record.push_back(C->varlist_size()); Record.push_back(C->getNumLoops()); diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 63f0d70..0ba3c05 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -3254,9 +3254,6 @@ bool ConditionBRVisitor::printValue(const Expr *CondVarExpr, raw_ostream &Out, return true; } -constexpr llvm::StringLiteral ConditionBRVisitor::GenericTrueMessage; -constexpr llvm::StringLiteral ConditionBRVisitor::GenericFalseMessage; - bool ConditionBRVisitor::isPieceMessageGeneric( const PathDiagnosticPiece *Piece) { return Piece->getString() == GenericTrueMessage || diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp index eebecdb..4178d1f 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp @@ -1,4 +1,4 @@ -//===- DependencyScanner.cpp - Performs module dependency scanning --------===// +//===- DependencyScannerImpl.cpp - Implements module dependency scanning --===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -12,6 +12,7 @@ #include "clang/Driver/Driver.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/TargetParser/Host.h" using namespace clang; @@ -456,7 +457,8 @@ initVFSForTUBuferScanning(IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS, return std::make_pair(ModifiedFS, ModifiedCommandLine); } -std::pair<IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::vector<std::string>> +std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>, + std::vector<std::string>> initVFSForByNameScanning(IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS, ArrayRef<std::string> CommandLine, StringRef WorkingDirectory, StringRef ModuleName) { @@ -588,7 +590,7 @@ computePrebuiltModulesASTMap(CompilerInstance &ScanInstance, } std::unique_ptr<DependencyOutputOptions> -takeDependencyOutputOptionsFrom(CompilerInstance &ScanInstance) { +takeAndUpdateDependencyOutputOptionsFrom(CompilerInstance &ScanInstance) { // This function moves the existing dependency output options from the // invocation to the collector. The options in the invocation are reset, // which ensures that the compiler won't create new dependency collectors, @@ -675,7 +677,7 @@ bool DependencyScanningAction::runInvocation( if (!MaybePrebuiltModulesASTMap) return false; - auto DepOutputOpts = takeDependencyOutputOptionsFrom(ScanInstance); + auto DepOutputOpts = takeAndUpdateDependencyOutputOptionsFrom(ScanInstance); MDC = initializeScanInstanceDependencyCollector( ScanInstance, std::move(DepOutputOpts), WorkingDirectory, Consumer, @@ -686,8 +688,6 @@ bool DependencyScanningAction::runInvocation( if (Service.getFormat() == ScanningOutputFormat::P1689) Action = std::make_unique<PreprocessOnlyAction>(); - else if (ModuleName) - Action = std::make_unique<GetDependenciesByModuleNameAction>(*ModuleName); else Action = std::make_unique<ReadPCHAndPreprocessAction>(); @@ -704,3 +704,175 @@ bool DependencyScanningAction::runInvocation( return Result; } + +bool CompilerInstanceWithContext::initialize(DiagnosticConsumer *DC) { + if (DC) { + DiagConsumer = DC; + } else { + DiagPrinterWithOS = + std::make_unique<TextDiagnosticsPrinterWithOutput>(CommandLine); + DiagConsumer = &DiagPrinterWithOS->DiagPrinter; + } + + std::tie(OverlayFS, CommandLine) = initVFSForByNameScanning( + Worker.BaseFS, CommandLine, CWD, "ScanningByName"); + + DiagEngineWithCmdAndOpts = std::make_unique<DignosticsEngineWithDiagOpts>( + CommandLine, OverlayFS, *DiagConsumer); + + std::tie(Driver, Compilation) = buildCompilation( + CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, OverlayFS, Alloc); + + if (!Compilation) + return false; + + assert(Compilation->getJobs().size() && + "Must have a job list of non-zero size"); + const driver::Command &Command = *(Compilation->getJobs().begin()); + const auto &CommandArgs = Command.getArguments(); + assert(!CommandArgs.empty() && "Cannot have a command with 0 args"); + assert(StringRef(CommandArgs[0]) == "-cc1" && "Requires a cc1 job."); + OriginalInvocation = std::make_unique<CompilerInvocation>(); + + if (!CompilerInvocation::CreateFromArgs(*OriginalInvocation, CommandArgs, + *DiagEngineWithCmdAndOpts->DiagEngine, + Command.getExecutable())) { + DiagEngineWithCmdAndOpts->DiagEngine->Report( + diag::err_fe_expected_compiler_job) + << llvm::join(CommandLine, " "); + return false; + } + + if (any(Worker.Service.getOptimizeArgs() & ScanningOptimizations::Macros)) + canonicalizeDefines(OriginalInvocation->getPreprocessorOpts()); + + // Create the CompilerInstance. + IntrusiveRefCntPtr<ModuleCache> ModCache = + makeInProcessModuleCache(Worker.Service.getModuleCacheEntries()); + CIPtr = std::make_unique<CompilerInstance>( + std::make_shared<CompilerInvocation>(*OriginalInvocation), + Worker.PCHContainerOps, ModCache.get()); + auto &CI = *CIPtr; + + if (!initializeScanCompilerInstance( + CI, OverlayFS, DiagEngineWithCmdAndOpts->DiagEngine->getClient(), + Worker.Service, Worker.DepFS)) + return false; + + StableDirs = getInitialStableDirs(CI); + auto MaybePrebuiltModulesASTMap = + computePrebuiltModulesASTMap(CI, StableDirs); + if (!MaybePrebuiltModulesASTMap) + return false; + + PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap); + OutputOpts = takeAndUpdateDependencyOutputOptionsFrom(CI); + + // We do not create the target in initializeScanCompilerInstance because + // setting it here is unique for by-name lookups. We create the target only + // once here, and the information is reused for all computeDependencies calls. + // We do not need to call createTarget explicitly if we go through + // CompilerInstance::ExecuteAction to perform scanning. + CI.createTarget(); + + return true; +} + +bool CompilerInstanceWithContext::computeDependencies( + StringRef ModuleName, DependencyConsumer &Consumer, + DependencyActionController &Controller) { + assert(CIPtr && "CIPtr must be initialized before calling this method"); + auto &CI = *CIPtr; + + // We create this cleanup object because computeDependencies may exit + // early with errors. + auto CleanUp = llvm::make_scope_exit([&]() { + CI.clearDependencyCollectors(); + // The preprocessor may not be created at the entry of this method, + // but it must have been created when this method returns, whether + // there are errors during scanning or not. + CI.getPreprocessor().removePPCallbacks(); + }); + + auto MDC = initializeScanInstanceDependencyCollector( + CI, std::make_unique<DependencyOutputOptions>(*OutputOpts), CWD, Consumer, + Worker.Service, + /* The MDC's constructor makes a copy of the OriginalInvocation, so + we can pass it in without worrying that it might be changed across + invocations of computeDependencies. */ + *OriginalInvocation, Controller, PrebuiltModuleASTMap, StableDirs); + + if (!SrcLocOffset) { + // When SrcLocOffset is zero, we are at the beginning of the fake source + // file. In this case, we call BeginSourceFile to initialize. + std::unique_ptr<FrontendAction> Action = + std::make_unique<PreprocessOnlyAction>(); + auto InputFile = CI.getFrontendOpts().Inputs.begin(); + bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile); + assert(ActionBeginSucceeded && "Action BeginSourceFile must succeed"); + (void)ActionBeginSucceeded; + } + + Preprocessor &PP = CI.getPreprocessor(); + SourceManager &SM = PP.getSourceManager(); + FileID MainFileID = SM.getMainFileID(); + SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID); + SourceLocation IDLocation = FileStart.getLocWithOffset(SrcLocOffset); + PPCallbacks *CB = nullptr; + if (!SrcLocOffset) { + // We need to call EnterSourceFile when SrcLocOffset is zero to initialize + // the preprocessor. + bool PPFailed = PP.EnterSourceFile(MainFileID, nullptr, SourceLocation()); + assert(!PPFailed && "Preprocess must be able to enter the main file."); + (void)PPFailed; + CB = MDC->getPPCallbacks(); + } else { + // When SrcLocOffset is non-zero, the preprocessor has already been + // initialized through a previous call of computeDependencies. We want to + // preserve the PP's state, hence we do not call EnterSourceFile again. + MDC->attachToPreprocessor(PP); + CB = MDC->getPPCallbacks(); + + FileID PrevFID; + SrcMgr::CharacteristicKind FileType = SM.getFileCharacteristic(IDLocation); + CB->LexedFileChanged(MainFileID, + PPChainedCallbacks::LexedFileChangeReason::EnterFile, + FileType, PrevFID, IDLocation); + } + + SrcLocOffset++; + SmallVector<IdentifierLoc, 2> Path; + IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName); + Path.emplace_back(IDLocation, ModuleID); + auto ModResult = CI.loadModule(IDLocation, Path, Module::Hidden, false); + + assert(CB && "Must have PPCallbacks after module loading"); + CB->moduleImport(SourceLocation(), Path, ModResult); + // Note that we are calling the CB's EndOfMainFile function, which + // forwards the results to the dependency consumer. + // It does not indicate the end of processing the fake file. + CB->EndOfMainFile(); + + if (!ModResult) + return false; + + CompilerInvocation ModuleInvocation(*OriginalInvocation); + MDC->applyDiscoveredDependencies(ModuleInvocation); + Consumer.handleBuildCommand( + {CommandLine[0], ModuleInvocation.getCC1CommandLine()}); + + return true; +} + +bool CompilerInstanceWithContext::finalize() { + DiagConsumer->finish(); + return true; +} + +llvm::Error CompilerInstanceWithContext::handleReturnStatus(bool Success) { + assert(DiagPrinterWithOS && "Must use the default DiagnosticConsumer."); + return Success ? llvm::Error::success() + : llvm::make_error<llvm::StringError>( + DiagPrinterWithOS->DiagnosticsOS.str(), + llvm::inconvertibleErrorCode()); +} diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h index 5657317..54166da 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h +++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h @@ -1,4 +1,4 @@ -//===- DependencyScanner.h - Performs module dependency scanning *- C++ -*-===// +//===- DependencyScannerImpl.h - Implements dependency scanning *- C++ -*--===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -23,6 +23,8 @@ class DiagnosticConsumer; namespace tooling { namespace dependencies { class DependencyScanningService; +class DependencyScanningWorker; + class DependencyConsumer; class DependencyActionController; class DependencyScanningWorkerFilesystem; @@ -35,8 +37,7 @@ public: IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS, std::optional<StringRef> ModuleName = std::nullopt) : Service(Service), WorkingDirectory(WorkingDirectory), - Consumer(Consumer), Controller(Controller), DepFS(std::move(DepFS)), - ModuleName(ModuleName) {} + Consumer(Consumer), Controller(Controller), DepFS(std::move(DepFS)) {} bool runInvocation(std::unique_ptr<CompilerInvocation> Invocation, IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS, std::shared_ptr<PCHContainerOperations> PCHContainerOps, @@ -66,7 +67,6 @@ private: DependencyConsumer &Consumer; DependencyActionController &Controller; IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS; - std::optional<StringRef> ModuleName; std::optional<CompilerInstance> ScanInstanceStorage; std::shared_ptr<ModuleDepCollector> MDC; std::vector<std::string> LastCC1Arguments; @@ -118,7 +118,8 @@ initVFSForTUBuferScanning(IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS, StringRef WorkingDirectory, llvm::MemoryBufferRef TUBuffer); -std::pair<IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::vector<std::string>> +std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>, + std::vector<std::string>> initVFSForByNameScanning(IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS, ArrayRef<std::string> CommandLine, StringRef WorkingDirectory, StringRef ModuleName); @@ -137,7 +138,7 @@ computePrebuiltModulesASTMap(CompilerInstance &ScanInstance, SmallVector<StringRef> &StableDirs); std::unique_ptr<DependencyOutputOptions> -takeDependencyOutputOptionsFrom(CompilerInstance &ScanInstance); +takeAndUpdateDependencyOutputOptionsFrom(CompilerInstance &ScanInstance); /// Create the dependency collector that will collect the produced /// dependencies. May return the created ModuleDepCollector depending @@ -150,6 +151,60 @@ std::shared_ptr<ModuleDepCollector> initializeScanInstanceDependencyCollector( DependencyActionController &Controller, PrebuiltModulesAttrsMap PrebuiltModulesASTMap, llvm::SmallVector<StringRef> &StableDirs); + +class CompilerInstanceWithContext { + // Context + DependencyScanningWorker &Worker; + llvm::StringRef CWD; + std::vector<std::string> CommandLine; + + // Context - file systems + llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS; + + // Context - Diagnostics engine. + std::unique_ptr<TextDiagnosticsPrinterWithOutput> DiagPrinterWithOS; + // DiagConsumer may points to DiagPrinterWithOS->DiagPrinter, or a custom + // DiagnosticConsumer passed in from initialize. + DiagnosticConsumer *DiagConsumer = nullptr; + std::unique_ptr<DignosticsEngineWithDiagOpts> DiagEngineWithCmdAndOpts; + + // Context - compiler invocation + // Compilation's command's arguments may be owned by Alloc when expanded from + // response files, so we need to keep Alloc alive in the context. + llvm::BumpPtrAllocator Alloc; + std::unique_ptr<clang::driver::Driver> Driver; + std::unique_ptr<clang::driver::Compilation> Compilation; + std::unique_ptr<CompilerInvocation> OriginalInvocation; + + // Context - output options + std::unique_ptr<DependencyOutputOptions> OutputOpts; + + // Context - stable directory handling + llvm::SmallVector<StringRef> StableDirs; + PrebuiltModulesAttrsMap PrebuiltModuleASTMap; + + // Compiler Instance + std::unique_ptr<CompilerInstance> CIPtr; + + // Source location offset. + int32_t SrcLocOffset = 0; + +public: + CompilerInstanceWithContext(DependencyScanningWorker &Worker, StringRef CWD, + const std::vector<std::string> &CMD) + : Worker(Worker), CWD(CWD), CommandLine(CMD) {}; + + // The three methods below returns false when they fail, with the detail + // accumulated in DiagConsumer. + bool initialize(DiagnosticConsumer *DC); + bool computeDependencies(StringRef ModuleName, DependencyConsumer &Consumer, + DependencyActionController &Controller); + bool finalize(); + + // The method below turns the return status from the above methods + // into an llvm::Error using a default DiagnosticConsumer. + llvm::Error handleReturnStatus(bool Success); +}; } // namespace dependencies } // namespace tooling } // namespace clang diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp index 27734ff..a1f2db7 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp @@ -162,13 +162,45 @@ DependencyScanningTool::getModuleDependencies( LookupModuleOutputCallback LookupModuleOutput) { FullDependencyConsumer Consumer(AlreadySeen); CallbackActionController Controller(LookupModuleOutput); - llvm::Error Result = Worker.computeDependencies(CWD, CommandLine, Consumer, - Controller, ModuleName); + if (auto Error = + Worker.initializeCompilerInstanceWithContextOrError(CWD, CommandLine)) + return std::move(Error); + + auto Result = Worker.computeDependenciesByNameWithContextOrError( + ModuleName, Consumer, Controller); + + if (auto Error = Worker.finalizeCompilerInstanceWithContextOrError()) + return std::move(Error); + if (Result) return std::move(Result); + return Consumer.takeTranslationUnitDeps(); } +llvm::Error DependencyScanningTool::initializeCompilerInstanceWithContext( + StringRef CWD, const std::vector<std::string> &CommandLine) { + return Worker.initializeCompilerInstanceWithContextOrError(CWD, CommandLine); +} + +llvm::Expected<TranslationUnitDeps> +DependencyScanningTool::computeDependenciesByNameWithContext( + StringRef ModuleName, const llvm::DenseSet<ModuleID> &AlreadySeen, + LookupModuleOutputCallback LookupModuleOutput) { + FullDependencyConsumer Consumer(AlreadySeen); + CallbackActionController Controller(LookupModuleOutput); + llvm::Error Result = Worker.computeDependenciesByNameWithContextOrError( + ModuleName, Consumer, Controller); + if (Result) + return std::move(Result); + + return Consumer.takeTranslationUnitDeps(); +} + +llvm::Error DependencyScanningTool::finalizeCompilerInstanceWithContext() { + return Worker.finalizeCompilerInstanceWithContextOrError(); +} + TranslationUnitDeps FullDependencyConsumer::takeTranslationUnitDeps() { TranslationUnitDeps TU; diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 0a1cf6b..dc408b1 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -43,6 +43,9 @@ DependencyScanningWorker::DependencyScanningWorker( } } +DependencyScanningWorker::~DependencyScanningWorker() = default; +DependencyActionController::~DependencyActionController() = default; + llvm::Error DependencyScanningWorker::computeDependencies( StringRef WorkingDirectory, const std::vector<std::string> &CommandLine, DependencyConsumer &Consumer, DependencyActionController &Controller, @@ -58,21 +61,6 @@ llvm::Error DependencyScanningWorker::computeDependencies( DiagPrinterWithOS.DiagnosticsOS.str(), llvm::inconvertibleErrorCode()); } -llvm::Error DependencyScanningWorker::computeDependencies( - StringRef WorkingDirectory, const std::vector<std::string> &CommandLine, - DependencyConsumer &Consumer, DependencyActionController &Controller, - StringRef ModuleName) { - // Capture the emitted diagnostics and report them to the client - // in the case of a failure. - TextDiagnosticsPrinterWithOutput DiagPrinterWithOS(CommandLine); - - if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller, - DiagPrinterWithOS.DiagPrinter, ModuleName)) - return llvm::Error::success(); - return llvm::make_error<llvm::StringError>( - DiagPrinterWithOS.DiagnosticsOS.str(), llvm::inconvertibleErrorCode()); -} - static bool forEachDriverJob( ArrayRef<std::string> ArgStrs, DiagnosticsEngine &Diags, IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS, @@ -113,11 +101,11 @@ static bool createAndRunToolInvocation( bool DependencyScanningWorker::scanDependencies( StringRef WorkingDirectory, const std::vector<std::string> &CommandLine, DependencyConsumer &Consumer, DependencyActionController &Controller, - DiagnosticConsumer &DC, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS, - std::optional<StringRef> ModuleName) { + DiagnosticConsumer &DC, + llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) { DignosticsEngineWithDiagOpts DiagEngineWithCmdAndOpts(CommandLine, FS, DC); DependencyScanningAction Action(Service, WorkingDirectory, Consumer, - Controller, DepFS, ModuleName); + Controller, DepFS); bool Success = false; if (CommandLine[1] == "-cc1") { @@ -172,24 +160,51 @@ bool DependencyScanningWorker::computeDependencies( auto [FinalFS, FinalCommandLine] = initVFSForTUBuferScanning( BaseFS, CommandLine, WorkingDirectory, *TUBuffer); return scanDependencies(WorkingDirectory, FinalCommandLine, Consumer, - Controller, DC, FinalFS, - /*ModuleName=*/std::nullopt); + Controller, DC, FinalFS); } else { BaseFS->setCurrentWorkingDirectory(WorkingDirectory); return scanDependencies(WorkingDirectory, CommandLine, Consumer, Controller, - DC, BaseFS, /*ModuleName=*/std::nullopt); + DC, BaseFS); } } -bool DependencyScanningWorker::computeDependencies( - StringRef WorkingDirectory, const std::vector<std::string> &CommandLine, - DependencyConsumer &Consumer, DependencyActionController &Controller, - DiagnosticConsumer &DC, StringRef ModuleName) { - auto [OverlayFS, ModifiedCommandLine] = initVFSForByNameScanning( - BaseFS, CommandLine, WorkingDirectory, ModuleName); +llvm::Error +DependencyScanningWorker::initializeCompilerInstanceWithContextOrError( + StringRef CWD, const std::vector<std::string> &CommandLine) { + bool Success = initializeCompilerInstanceWithContext(CWD, CommandLine); + return CIWithContext->handleReturnStatus(Success); +} + +llvm::Error +DependencyScanningWorker::computeDependenciesByNameWithContextOrError( + StringRef ModuleName, DependencyConsumer &Consumer, + DependencyActionController &Controller) { + bool Success = + computeDependenciesByNameWithContext(ModuleName, Consumer, Controller); + return CIWithContext->handleReturnStatus(Success); +} + +llvm::Error +DependencyScanningWorker::finalizeCompilerInstanceWithContextOrError() { + bool Success = finalizeCompilerInstance(); + return CIWithContext->handleReturnStatus(Success); +} - return scanDependencies(WorkingDirectory, ModifiedCommandLine, Consumer, - Controller, DC, OverlayFS, ModuleName); +bool DependencyScanningWorker::initializeCompilerInstanceWithContext( + StringRef CWD, const std::vector<std::string> &CommandLine, + DiagnosticConsumer *DC) { + CIWithContext = + std::make_unique<CompilerInstanceWithContext>(*this, CWD, CommandLine); + return CIWithContext->initialize(DC); } -DependencyActionController::~DependencyActionController() {} +bool DependencyScanningWorker::computeDependenciesByNameWithContext( + StringRef ModuleName, DependencyConsumer &Consumer, + DependencyActionController &Controller) { + assert(CIWithContext && "CompilerInstance with context required!"); + return CIWithContext->computeDependencies(ModuleName, Consumer, Controller); +} + +bool DependencyScanningWorker::finalizeCompilerInstance() { + return CIWithContext->finalize(); +} diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp index a117bec..e07a208 100644 --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -965,7 +965,9 @@ ModuleDepCollector::ModuleDepCollector( makeCommonInvocationForModuleBuild(std::move(OriginalCI))) {} void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) { - PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this)); + auto CollectorPP = std::make_unique<ModuleDepCollectorPP>(*this); + CollectorPPPtr = CollectorPP.get(); + PP.addPPCallbacks(std::move(CollectorPP)); } void ModuleDepCollector::attachToASTReader(ASTReader &R) {} diff --git a/clang/lib/Tooling/Syntax/TokenBufferTokenManager.cpp b/clang/lib/Tooling/Syntax/TokenBufferTokenManager.cpp index a06f7e2..3d63d4a 100644 --- a/clang/lib/Tooling/Syntax/TokenBufferTokenManager.cpp +++ b/clang/lib/Tooling/Syntax/TokenBufferTokenManager.cpp @@ -10,8 +10,6 @@ namespace clang { namespace syntax { -constexpr llvm::StringLiteral syntax::TokenBufferTokenManager::Kind; - std::pair<FileID, ArrayRef<syntax::Token>> syntax::TokenBufferTokenManager::lexBuffer( std::unique_ptr<llvm::MemoryBuffer> Input) { |
