diff options
Diffstat (limited to 'clang/lib')
35 files changed, 1133 insertions, 450 deletions
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 4e63400..84f7e62 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -6007,6 +6007,8 @@ bool Compiler<Emitter>::visitSwitchStmt(const SwitchStmt *S) { CaseLabels[SC] = this->getLabel(); const Expr *Value = CS->getLHS(); + if (Value->isValueDependent()) + return false; PrimType ValueT = this->classifyPrim(Value->getType()); // Compare the case statement's value to the switch condition. diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 8fab6ef..4f6f52b 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) { @@ -5452,10 +5821,13 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info, } const CaseStmt *CS = cast<CaseStmt>(SC); - APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx); - APSInt RHS = CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx) - : LHS; - if (LHS <= Value && Value <= RHS) { + const Expr *LHS = CS->getLHS(); + const Expr *RHS = CS->getRHS(); + if (LHS->isValueDependent() || (RHS && RHS->isValueDependent())) + return ESR_Failed; + APSInt LHSValue = LHS->EvaluateKnownConstInt(Info.Ctx); + APSInt RHSValue = RHS ? RHS->EvaluateKnownConstInt(Info.Ctx) : LHSValue; + if (LHSValue <= Value && Value <= RHSValue) { Found = SC; break; } @@ -8667,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)) @@ -10851,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; + } } } @@ -11346,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); } @@ -13313,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); @@ -13383,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( @@ -17189,7 +17692,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: @@ -17336,6 +17838,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"); @@ -17873,6 +18390,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( @@ -17911,6 +18431,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/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 42f124b..0874b3d 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -954,6 +954,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, CXXTryStmt> cxxTryStmt; const internal::VariadicDynCastAllOfMatcher<Stmt, CXXThrowExpr> cxxThrowExpr; const internal::VariadicDynCastAllOfMatcher<Stmt, NullStmt> nullStmt; const internal::VariadicDynCastAllOfMatcher<Stmt, AsmStmt> asmStmt; +const internal::VariadicDynCastAllOfMatcher<Decl, FileScopeAsmDecl> + fileScopeAsmDecl; const internal::VariadicDynCastAllOfMatcher<Stmt, CXXBoolLiteralExpr> cxxBoolLiteral; const internal::VariadicDynCastAllOfMatcher<Stmt, StringLiteral> stringLiteral; diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 01c03f3..66848f7 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -246,6 +246,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(expr); REGISTER_MATCHER(exprWithCleanups); REGISTER_MATCHER(fieldDecl); + REGISTER_MATCHER(fileScopeAsmDecl); REGISTER_MATCHER(fixedPointLiteral); REGISTER_MATCHER(floatLiteral); REGISTER_MATCHER(forCallable); 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/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 0803910..4e6a5ee 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -481,6 +481,19 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, return emitCall(e->getCallee()->getType(), CIRGenCallee::forDirect(fnOp), e, returnValue); } + case Builtin::BI__builtin_dynamic_object_size: + case Builtin::BI__builtin_object_size: { + unsigned type = + e->getArg(1)->EvaluateKnownConstInt(getContext()).getZExtValue(); + auto resType = mlir::cast<cir::IntType>(convertType(e->getType())); + + // We pass this builtin onto the optimizer so that it can figure out the + // object size in more complex cases. + bool isDynamic = builtinID == Builtin::BI__builtin_dynamic_object_size; + return RValue::get(emitBuiltinObjectSize(e->getArg(0), type, resType, + /*EmittedE=*/nullptr, isDynamic)); + } + case Builtin::BI__builtin_prefetch: { auto evaluateOperandAsInt = [&](const Expr *arg) { Expr::EvalResult res; @@ -663,3 +676,42 @@ mlir::Value CIRGenFunction::emitVAArg(VAArgExpr *ve) { mlir::Value vaList = emitVAListRef(ve->getSubExpr()).getPointer(); return cir::VAArgOp::create(builder, loc, type, vaList); } + +mlir::Value CIRGenFunction::emitBuiltinObjectSize(const Expr *e, unsigned type, + cir::IntType resType, + mlir::Value emittedE, + bool isDynamic) { + assert(!cir::MissingFeatures::opCallImplicitObjectSizeArgs()); + + // LLVM can't handle type=3 appropriately, and __builtin_object_size shouldn't + // evaluate e for side-effects. In either case, just like original LLVM + // lowering, we shouldn't lower to `cir.objsize` but to a constant instead. + if (type == 3 || (!emittedE && e->HasSideEffects(getContext()))) + return builder.getConstInt(getLoc(e->getSourceRange()), resType, + (type & 2) ? 0 : -1); + + mlir::Value ptr = emittedE ? emittedE : emitScalarExpr(e); + assert(mlir::isa<cir::PointerType>(ptr.getType()) && + "Non-pointer passed to __builtin_object_size?"); + + assert(!cir::MissingFeatures::countedBySize()); + + // Extract the min/max mode from type. CIR only supports type 0 + // (max, whole object) and type 2 (min, whole object), not type 1 or 3 + // (closest subobject variants). + const bool min = ((type & 2) != 0); + // For GCC compatibility, __builtin_object_size treats NULL as unknown size. + auto op = + cir::ObjSizeOp::create(builder, getLoc(e->getSourceRange()), resType, ptr, + min, /*nullUnknown=*/true, isDynamic); + return op.getResult(); +} + +mlir::Value CIRGenFunction::evaluateOrEmitBuiltinObjectSize( + const Expr *e, unsigned type, cir::IntType resType, mlir::Value emittedE, + bool isDynamic) { + uint64_t objectSize; + if (!e->tryEvaluateObjectSize(objectSize, getContext(), type)) + return emitBuiltinObjectSize(e, type, resType, emittedE, isDynamic); + return builder.getConstInt(getLoc(e->getSourceRange()), resType, objectSize); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 1c52a78..f879e58 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1307,6 +1307,28 @@ public: RValue emitBuiltinExpr(const clang::GlobalDecl &gd, unsigned builtinID, const clang::CallExpr *e, ReturnValueSlot returnValue); + /// Returns a Value corresponding to the size of the given expression by + /// emitting a `cir.objsize` operation. + /// + /// \param e The expression whose object size to compute + /// \param type Determines the semantics of the object size computation. + /// The type parameter is a 2-bit value where: + /// bit 0 (type & 1): 0 = whole object, 1 = closest subobject + /// bit 1 (type & 2): 0 = maximum size, 2 = minimum size + /// \param resType The result type for the size value + /// \param emittedE Optional pre-emitted pointer value. If non-null, we'll + /// call `cir.objsize` on this value rather than emitting e. + /// \param isDynamic If true, allows runtime evaluation via dynamic mode + mlir::Value emitBuiltinObjectSize(const clang::Expr *e, unsigned type, + cir::IntType resType, mlir::Value emittedE, + bool isDynamic); + + mlir::Value evaluateOrEmitBuiltinObjectSize(const clang::Expr *e, + unsigned type, + cir::IntType resType, + mlir::Value emittedE, + bool isDynamic); + RValue emitCall(const CIRGenFunctionInfo &funcInfo, const CIRGenCallee &callee, ReturnValueSlot returnValue, const CallArgList &args, cir::CIRCallOpInterface *callOp, diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index ba967a4..b4afed7 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2832,6 +2832,29 @@ static void collectUnreachable(mlir::Operation *parent, } } +mlir::LogicalResult CIRToLLVMObjSizeOpLowering::matchAndRewrite( + cir::ObjSizeOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::Type llvmResTy = getTypeConverter()->convertType(op.getType()); + mlir::Location loc = op->getLoc(); + + mlir::IntegerType i1Ty = rewriter.getI1Type(); + + auto i1Val = [&rewriter, &loc, &i1Ty](bool val) { + return mlir::LLVM::ConstantOp::create(rewriter, loc, i1Ty, val); + }; + + replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.objectsize", llvmResTy, + { + adaptor.getPtr(), + i1Val(op.getMin()), + i1Val(op.getNullunknown()), + i1Val(op.getDynamic()), + }); + + return mlir::LogicalResult::success(); +} + void ConvertCIRToLLVMPass::processCIRAttrs(mlir::ModuleOp module) { // Lower the module attributes to LLVM equivalents. if (mlir::Attribute tripleAttr = diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 945f9e2..e392a12 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -549,6 +549,16 @@ static void addSPIRVBuiltinDecoration(llvm::GlobalVariable *GV, GV->addMetadata("spirv.Decorations", *Decoration); } +static void addLocationDecoration(llvm::GlobalVariable *GV, unsigned Location) { + LLVMContext &Ctx = GV->getContext(); + IRBuilder<> B(GV->getContext()); + MDNode *Operands = + MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(/* Location */ 30)), + ConstantAsMetadata::get(B.getInt32(Location))}); + MDNode *Decoration = MDNode::get(Ctx, {Operands}); + GV->addMetadata("spirv.Decorations", *Decoration); +} + static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M, llvm::Type *Ty, const Twine &Name, unsigned BuiltInID) { @@ -562,6 +572,69 @@ static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M, return B.CreateLoad(Ty, GV); } +static llvm::Value *createSPIRVLocationLoad(IRBuilder<> &B, llvm::Module &M, + llvm::Type *Ty, unsigned Location, + StringRef Name) { + auto *GV = new llvm::GlobalVariable( + M, Ty, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage, + /* Initializer= */ nullptr, /* Name= */ Name, /* insertBefore= */ nullptr, + llvm::GlobalVariable::GeneralDynamicTLSModel, + /* AddressSpace */ 7, /* isExternallyInitialized= */ true); + GV->setVisibility(llvm::GlobalValue::HiddenVisibility); + addLocationDecoration(GV, Location); + return B.CreateLoad(Ty, GV); +} + +llvm::Value * +CGHLSLRuntime::emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, + HLSLSemanticAttr *Semantic, + std::optional<unsigned> Index) { + Twine BaseName = Twine(Semantic->getAttrName()->getName()); + Twine VariableName = BaseName.concat(Twine(Index.value_or(0))); + + unsigned Location = SPIRVLastAssignedInputSemanticLocation; + + // DXC completely ignores the semantic/index pair. Location are assigned from + // the first semantic to the last. + llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Type); + unsigned ElementCount = AT ? AT->getNumElements() : 1; + SPIRVLastAssignedInputSemanticLocation += ElementCount; + return createSPIRVLocationLoad(B, CGM.getModule(), Type, Location, + VariableName.str()); +} + +llvm::Value * +CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, + HLSLSemanticAttr *Semantic, + std::optional<unsigned> Index) { + Twine BaseName = Twine(Semantic->getAttrName()->getName()); + Twine VariableName = BaseName.concat(Twine(Index.value_or(0))); + + // DXIL packing rules etc shall be handled here. + // FIXME: generate proper sigpoint, index, col, row values. + // FIXME: also DXIL loads vectors element by element. + SmallVector<Value *> Args{B.getInt32(4), B.getInt32(0), B.getInt32(0), + B.getInt8(0), + llvm::PoisonValue::get(B.getInt32Ty())}; + + llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_load_input; + llvm::Value *Value = B.CreateIntrinsic(/*ReturnType=*/Type, IntrinsicID, Args, + nullptr, VariableName); + return Value; +} + +llvm::Value *CGHLSLRuntime::emitUserSemanticLoad( + IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl, + HLSLSemanticAttr *Semantic, std::optional<unsigned> Index) { + if (CGM.getTarget().getTriple().isSPIRV()) + return emitSPIRVUserSemanticLoad(B, Type, Semantic, Index); + + if (CGM.getTarget().getTriple().isDXIL()) + return emitDXILUserSemanticLoad(B, Type, Semantic, Index); + + llvm_unreachable("Unsupported target for user-semantic load."); +} + llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad( IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl, Attr *Semantic, std::optional<unsigned> Index) { @@ -626,6 +699,9 @@ CGHLSLRuntime::handleScalarSemanticLoad(IRBuilder<> &B, const FunctionDecl *FD, std::optional<unsigned> Index = std::nullopt; if (Semantic->isSemanticIndexExplicit()) Index = Semantic->getSemanticIndex(); + + if (isa<HLSLUserSemanticAttr>(Semantic)) + return emitUserSemanticLoad(B, Type, Decl, Semantic, Index); return emitSystemSemanticLoad(B, Type, Decl, Semantic, Index); } diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index d35df52..9d31714 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -200,9 +200,25 @@ private: llvm::GlobalVariable *BufGV); void initializeBufferFromBinding(const HLSLBufferDecl *BufDecl, llvm::GlobalVariable *GV); + void initializeBufferFromBinding(const HLSLBufferDecl *BufDecl, + llvm::GlobalVariable *GV, + HLSLResourceBindingAttr *RBA); + + llvm::Value *emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, + HLSLSemanticAttr *Semantic, + std::optional<unsigned> Index); + llvm::Value *emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, + HLSLSemanticAttr *Semantic, + std::optional<unsigned> Index); + llvm::Value *emitUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, + const clang::DeclaratorDecl *Decl, + HLSLSemanticAttr *Semantic, + std::optional<unsigned> Index); + llvm::Triple::ArchType getArch(); llvm::DenseMap<const clang::RecordType *, llvm::TargetExtType *> LayoutTypes; + unsigned SPIRVLastAssignedInputSemanticLocation = 0; }; } // namespace CodeGen 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/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/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/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/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/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/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..3eb935c 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 = diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index b9707f0..a06c57b 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -775,6 +775,10 @@ HLSLSemanticAttr *SemaHLSL::createSemantic(const SemanticInfo &Info, DeclaratorDecl *TargetDecl) { std::string SemanticName = Info.Semantic->getAttrName()->getName().upper(); + if (dyn_cast<HLSLUserSemanticAttr>(Info.Semantic)) + return createSemanticAttr<HLSLUserSemanticAttr>(*Info.Semantic, TargetDecl, + Info.Index); + if (SemanticName == "SV_DISPATCHTHREADID") { return createSemanticAttr<HLSLSV_DispatchThreadIDAttr>( *Info.Semantic, TargetDecl, Info.Index); @@ -797,9 +801,10 @@ HLSLSemanticAttr *SemaHLSL::createSemantic(const SemanticInfo &Info, return nullptr; } -bool SemaHLSL::determineActiveSemanticOnScalar(FunctionDecl *FD, - DeclaratorDecl *D, - SemanticInfo &ActiveSemantic) { +bool SemaHLSL::determineActiveSemanticOnScalar( + FunctionDecl *FD, DeclaratorDecl *D, SemanticInfo &ActiveSemantic, + llvm::StringSet<> &ActiveInputSemantics) { + if (ActiveSemantic.Semantic == nullptr) { ActiveSemantic.Semantic = D->getAttr<HLSLSemanticAttr>(); if (ActiveSemantic.Semantic && @@ -818,11 +823,31 @@ bool SemaHLSL::determineActiveSemanticOnScalar(FunctionDecl *FD, checkSemanticAnnotation(FD, D, A); FD->addAttr(A); + + unsigned Location = ActiveSemantic.Index.value_or(0); + + const ConstantArrayType *AT = dyn_cast<ConstantArrayType>(D->getType()); + unsigned ElementCount = AT ? AT->getZExtSize() : 1; + ActiveSemantic.Index = Location + ElementCount; + + Twine BaseName = Twine(ActiveSemantic.Semantic->getAttrName()->getName()); + for (unsigned I = 0; I < ElementCount; ++I) { + Twine VariableName = BaseName.concat(Twine(Location + I)); + + auto [_, Inserted] = ActiveInputSemantics.insert(VariableName.str()); + if (!Inserted) { + Diag(D->getLocation(), diag::err_hlsl_semantic_index_overlap) + << VariableName.str(); + return false; + } + } + return true; } -bool SemaHLSL::determineActiveSemantic(FunctionDecl *FD, DeclaratorDecl *D, - SemanticInfo &ActiveSemantic) { +bool SemaHLSL::determineActiveSemantic( + FunctionDecl *FD, DeclaratorDecl *D, SemanticInfo &ActiveSemantic, + llvm::StringSet<> &ActiveInputSemantics) { if (ActiveSemantic.Semantic == nullptr) { ActiveSemantic.Semantic = D->getAttr<HLSLSemanticAttr>(); if (ActiveSemantic.Semantic && @@ -833,12 +858,13 @@ bool SemaHLSL::determineActiveSemantic(FunctionDecl *FD, DeclaratorDecl *D, const Type *T = D->getType()->getUnqualifiedDesugaredType(); const RecordType *RT = dyn_cast<RecordType>(T); if (!RT) - return determineActiveSemanticOnScalar(FD, D, ActiveSemantic); + return determineActiveSemanticOnScalar(FD, D, ActiveSemantic, + ActiveInputSemantics); const RecordDecl *RD = RT->getDecl(); for (FieldDecl *Field : RD->fields()) { SemanticInfo Info = ActiveSemantic; - if (!determineActiveSemantic(FD, Field, Info)) { + if (!determineActiveSemantic(FD, Field, Info, ActiveInputSemantics)) { Diag(Field->getLocation(), diag::note_hlsl_semantic_used_here) << Field; return false; } @@ -911,12 +937,14 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) { llvm_unreachable("Unhandled environment in triple"); } + llvm::StringSet<> ActiveInputSemantics; for (ParmVarDecl *Param : FD->parameters()) { SemanticInfo ActiveSemantic; ActiveSemantic.Semantic = nullptr; ActiveSemantic.Index = std::nullopt; - if (!determineActiveSemantic(FD, Param, ActiveSemantic)) { + if (!determineActiveSemantic(FD, Param, ActiveSemantic, + ActiveInputSemantics)) { Diag(Param->getLocation(), diag::note_previous_decl) << Param; FD->setInvalidDecl(); } @@ -947,6 +975,8 @@ void SemaHLSL::checkSemanticAnnotation(FunctionDecl *EntryPoint, return; DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Pixel}); break; + case attr::HLSLUserSemantic: + return; default: llvm_unreachable("Unknown SemanticAttr"); } @@ -1766,7 +1796,7 @@ void SemaHLSL::handleSemanticAttr(Decl *D, const ParsedAttr &AL) { if (AL.getAttrName()->getName().starts_with_insensitive("SV_")) diagnoseSystemSemanticAttr(D, AL, Index); else - Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL; + D->addAttr(createSemanticAttr<HLSLUserSemanticAttr>(AL, nullptr, Index)); } void SemaHLSL::handlePackOffsetAttr(Decl *D, const ParsedAttr &AL) { 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..de210c4 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -15824,16 +15824,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/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/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) { |
