diff options
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 21 | ||||
-rw-r--r-- | clang/lib/Sema/SemaConcept.cpp | 78 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 136 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 11 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOpenACC.cpp | 93 | ||||
-rw-r--r-- | clang/lib/Sema/SemaRISCV.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaStmtAttr.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 93 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 36 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 12 |
11 files changed, 312 insertions, 175 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 652527a..2990fd6 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -6926,13 +6926,13 @@ StringRef Sema::GetFormatStringTypeName(FormatStringType FST) { FormatStringType Sema::GetFormatStringType(StringRef Flavor) { return llvm::StringSwitch<FormatStringType>(Flavor) - .Cases("gnu_scanf", "scanf", FormatStringType::Scanf) - .Cases("gnu_printf", "printf", "printf0", "syslog", + .Cases({"gnu_scanf", "scanf"}, FormatStringType::Scanf) + .Cases({"gnu_printf", "printf", "printf0", "syslog"}, FormatStringType::Printf) - .Cases("NSString", "CFString", FormatStringType::NSString) - .Cases("gnu_strftime", "strftime", FormatStringType::Strftime) - .Cases("gnu_strfmon", "strfmon", FormatStringType::Strfmon) - .Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err", + .Cases({"NSString", "CFString"}, FormatStringType::NSString) + .Cases({"gnu_strftime", "strftime"}, FormatStringType::Strftime) + .Cases({"gnu_strfmon", "strfmon"}, FormatStringType::Strfmon) + .Cases({"kprintf", "cmn_err", "vcmn_err", "zcmn_err"}, FormatStringType::Kprintf) .Case("freebsd_kprintf", FormatStringType::FreeBSDKPrintf) .Case("os_trace", FormatStringType::OSLog) @@ -12309,13 +12309,20 @@ static void DiagnoseMixedUnicodeImplicitConversion(Sema &S, const Type *Source, SourceLocation CC) { assert(Source->isUnicodeCharacterType() && Target->isUnicodeCharacterType() && Source != Target); + + // Lone surrogates have a distinct representation in UTF-32. + // Converting between UTF-16 and UTF-32 codepoints seems very widespread, + // so don't warn on such conversion. + if (Source->isChar16Type() && Target->isChar32Type()) + return; + Expr::EvalResult Result; if (E->EvaluateAsInt(Result, S.getASTContext(), Expr::SE_AllowSideEffects, S.isConstantEvaluatedContext())) { llvm::APSInt Value(32); Value = Result.Val.getInt(); bool IsASCII = Value <= 0x7F; - bool IsBMP = Value <= 0xD7FF || (Value >= 0xE000 && Value <= 0xFFFF); + bool IsBMP = Value <= 0xDFFF || (Value >= 0xE000 && Value <= 0xFFFF); bool ConversionPreservesSemantics = IsASCII || (!Source->isChar8Type() && !Target->isChar8Type() && IsBMP); diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 04a73181..54cbfe4 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -432,7 +432,7 @@ private: // XXX: It is SLOW! Use it very carefully. std::optional<MultiLevelTemplateArgumentList> SubstitutionInTemplateArguments( const NormalizedConstraintWithParamMapping &Constraint, - MultiLevelTemplateArgumentList MLTAL, + const MultiLevelTemplateArgumentList &MLTAL, llvm::SmallVector<TemplateArgument> &SubstitutedOuterMost); ExprResult EvaluateSlow(const AtomicConstraint &Constraint, @@ -564,12 +564,17 @@ ExprResult ConstraintSatisfactionChecker::EvaluateAtomicConstraint( std::optional<MultiLevelTemplateArgumentList> ConstraintSatisfactionChecker::SubstitutionInTemplateArguments( const NormalizedConstraintWithParamMapping &Constraint, - MultiLevelTemplateArgumentList MLTAL, - llvm::SmallVector<TemplateArgument> &SubstitutedOuterMost) { + const MultiLevelTemplateArgumentList &MLTAL, + llvm::SmallVector<TemplateArgument> &SubstitutedOutermost) { if (!Constraint.hasParameterMapping()) return std::move(MLTAL); + // The mapping is empty, meaning no template arguments are needed for + // evaluation. + if (Constraint.getParameterMapping().empty()) + return MultiLevelTemplateArgumentList(); + TemplateDeductionInfo Info(Constraint.getBeginLoc()); Sema::InstantiatingTemplate Inst( S, Constraint.getBeginLoc(), @@ -607,7 +612,7 @@ ConstraintSatisfactionChecker::SubstitutionInTemplateArguments( // The empty MLTAL situation should only occur when evaluating non-dependent // constraints. if (MLTAL.getNumSubstitutedLevels()) - SubstitutedOuterMost = + SubstitutedOutermost = llvm::to_vector_of<TemplateArgument>(MLTAL.getOutermost()); unsigned Offset = 0; for (unsigned I = 0, MappedIndex = 0; I < Used.size(); I++) { @@ -615,19 +620,19 @@ ConstraintSatisfactionChecker::SubstitutionInTemplateArguments( if (Used[I]) Arg = S.Context.getCanonicalTemplateArgument( CTAI.SugaredConverted[MappedIndex++]); - if (I < SubstitutedOuterMost.size()) { - SubstitutedOuterMost[I] = Arg; + if (I < SubstitutedOutermost.size()) { + SubstitutedOutermost[I] = Arg; Offset = I + 1; } else { - SubstitutedOuterMost.push_back(Arg); - Offset = SubstitutedOuterMost.size(); + SubstitutedOutermost.push_back(Arg); + Offset = SubstitutedOutermost.size(); } } - if (Offset < SubstitutedOuterMost.size()) - SubstitutedOuterMost.erase(SubstitutedOuterMost.begin() + Offset); + if (Offset < SubstitutedOutermost.size()) + SubstitutedOutermost.erase(SubstitutedOutermost.begin() + Offset); MultiLevelTemplateArgumentList SubstitutedTemplateArgs; - SubstitutedTemplateArgs.addOuterTemplateArguments(TD, SubstitutedOuterMost, + SubstitutedTemplateArgs.addOuterTemplateArguments(TD, SubstitutedOutermost, /*Final=*/false); return std::move(SubstitutedTemplateArgs); } @@ -636,9 +641,9 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow( const AtomicConstraint &Constraint, const MultiLevelTemplateArgumentList &MLTAL) { - llvm::SmallVector<TemplateArgument> SubstitutedOuterMost; + llvm::SmallVector<TemplateArgument> SubstitutedOutermost; std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs = - SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOuterMost); + SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOutermost); if (!SubstitutedArgs) { Satisfaction.IsSatisfied = false; return ExprEmpty(); @@ -736,8 +741,9 @@ ExprResult ConstraintSatisfactionChecker::Evaluate( UnsubstitutedConstraintSatisfactionCacheResult Cache; Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors; Cache.Satisfaction.IsSatisfied = Satisfaction.IsSatisfied; - std::copy(Satisfaction.Details.begin() + Size, Satisfaction.Details.end(), - std::back_inserter(Cache.Satisfaction.Details)); + Cache.Satisfaction.Details.insert(Cache.Satisfaction.Details.end(), + Satisfaction.Details.begin() + Size, + Satisfaction.Details.end()); Cache.SubstExpr = E; S.UnsubstitutedConstraintSatisfactionCache.insert({ID, std::move(Cache)}); @@ -786,13 +792,13 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow( FoldExpandedConstraint::FoldOperatorKind::And; unsigned EffectiveDetailEndIndex = Satisfaction.Details.size(); - llvm::SmallVector<TemplateArgument> SubstitutedOuterMost; + llvm::SmallVector<TemplateArgument> SubstitutedOutermost; // FIXME: Is PackSubstitutionIndex correct? llvm::SaveAndRestore _(PackSubstitutionIndex, S.ArgPackSubstIndex); std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs = SubstitutionInTemplateArguments( static_cast<const NormalizedConstraintWithParamMapping &>(Constraint), - MLTAL, SubstitutedOuterMost); + MLTAL, SubstitutedOutermost); if (!SubstitutedArgs) { Satisfaction.IsSatisfied = false; return ExprError(); @@ -868,8 +874,9 @@ ExprResult ConstraintSatisfactionChecker::Evaluate( UnsubstitutedConstraintSatisfactionCacheResult Cache; Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors; Cache.Satisfaction.IsSatisfied = Satisfaction.IsSatisfied; - std::copy(Satisfaction.Details.begin() + Size, Satisfaction.Details.end(), - std::back_inserter(Cache.Satisfaction.Details)); + Cache.Satisfaction.Details.insert(Cache.Satisfaction.Details.end(), + Satisfaction.Details.begin() + Size, + Satisfaction.Details.end()); Cache.SubstExpr = E; S.UnsubstitutedConstraintSatisfactionCache.insert({ID, std::move(Cache)}); return E; @@ -880,9 +887,9 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow( const MultiLevelTemplateArgumentList &MLTAL, unsigned Size) { const ConceptReference *ConceptId = Constraint.getConceptId(); - llvm::SmallVector<TemplateArgument> SubstitutedOuterMost; + llvm::SmallVector<TemplateArgument> SubstitutedOutermost; std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs = - SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOuterMost); + SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOutermost); if (!SubstitutedArgs) { Satisfaction.IsSatisfied = false; @@ -1012,8 +1019,9 @@ ExprResult ConstraintSatisfactionChecker::Evaluate( UnsubstitutedConstraintSatisfactionCacheResult Cache; Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors; Cache.Satisfaction.IsSatisfied = Satisfaction.IsSatisfied; - std::copy(Satisfaction.Details.begin() + Size, Satisfaction.Details.end(), - std::back_inserter(Cache.Satisfaction.Details)); + Cache.Satisfaction.Details.insert(Cache.Satisfaction.Details.end(), + Satisfaction.Details.begin() + Size, + Satisfaction.Details.end()); Cache.SubstExpr = CE; S.UnsubstitutedConstraintSatisfactionCache.insert({ID, std::move(Cache)}); return CE; @@ -1217,10 +1225,10 @@ bool Sema::CheckConstraintSatisfaction( return false; } -static const ExprResult -SubstituteConceptsInConstrainExpression(Sema &S, const NamedDecl *D, - const ConceptSpecializationExpr *CSE, - UnsignedOrNone SubstIndex) { +static ExprResult +SubstituteConceptsInConstraintExpression(Sema &S, const NamedDecl *D, + const ConceptSpecializationExpr *CSE, + UnsignedOrNone SubstIndex) { // [C++2c] [temp.constr.normal] // Otherwise, to form CE, any non-dependent concept template argument Ai @@ -1255,7 +1263,7 @@ bool Sema::CheckConstraintSatisfaction( const ConceptSpecializationExpr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) { - ExprResult Res = SubstituteConceptsInConstrainExpression( + ExprResult Res = SubstituteConceptsInConstraintExpression( *this, nullptr, ConstraintExpr, ArgPackSubstIndex); if (!Res.isUsable()) return true; @@ -2017,8 +2025,13 @@ void SubstituteParameterMappings::buildParameterMapping( SemaRef.MarkUsedTemplateParameters(Args->arguments(), /*Depth=*/0, OccurringIndices); } + unsigned Size = OccurringIndices.count(); + // When the constraint is independent of any template parameters, + // we build an empty mapping so that we can distinguish these cases + // from cases where no mapping exists at all, e.g. when there are only atomic + // constraints. TemplateArgumentLoc *TempArgs = - new (SemaRef.Context) TemplateArgumentLoc[OccurringIndices.count()]; + new (SemaRef.Context) TemplateArgumentLoc[Size]; llvm::SmallVector<NamedDecl *> UsedParams; for (unsigned I = 0, J = 0, C = TemplateParams->size(); I != C; ++I) { SourceLocation Loc = ArgsAsWritten->NumTemplateArgs > I @@ -2039,7 +2052,6 @@ void SubstituteParameterMappings::buildParameterMapping( TemplateParams->getLAngleLoc(), UsedParams, /*RAngleLoc=*/SourceLocation(), /*RequiresClause=*/nullptr); - unsigned Size = OccurringIndices.count(); N.updateParameterMapping( std::move(OccurringIndices), std::move(OccurringIndicesForSubsumption), MutableArrayRef<TemplateArgumentLoc>{TempArgs, Size}, UsedList); @@ -2050,6 +2062,10 @@ bool SubstituteParameterMappings::substitute( if (!N.hasParameterMapping()) buildParameterMapping(N); + // If the parameter mapping is empty, there is nothing to substitute. + if (N.getParameterMapping().empty()) + return false; + SourceLocation InstLocBegin, InstLocEnd; llvm::ArrayRef Arguments = ArgsAsWritten->arguments(); if (Arguments.empty()) { @@ -2289,7 +2305,7 @@ NormalizedConstraint *NormalizedConstraint::fromConstraintExpr( ConceptDecl *CD = CSE->getNamedConcept()->getCanonicalDecl(); ExprResult Res = - SubstituteConceptsInConstrainExpression(S, D, CSE, SubstIndex); + SubstituteConceptsInConstraintExpression(S, D, CSE, SubstIndex); if (!Res.isUsable()) return nullptr; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 04d46d6..fc3aabf 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -7640,6 +7640,58 @@ static bool isMainVar(DeclarationName Name, VarDecl *VD) { VD->isExternC()); } +void Sema::CheckAsmLabel(Scope *S, Expr *E, StorageClass SC, + TypeSourceInfo *TInfo, VarDecl *NewVD) { + + // Quickly return if the function does not have an `asm` attribute. + if (E == nullptr) + return; + + // The parser guarantees this is a string. + StringLiteral *SE = cast<StringLiteral>(E); + StringRef Label = SE->getString(); + QualType R = TInfo->getType(); + if (S->getFnParent() != nullptr) { + switch (SC) { + case SC_None: + case SC_Auto: + Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label; + break; + case SC_Register: + // Local Named register + if (!Context.getTargetInfo().isValidGCCRegisterName(Label) && + DeclAttrsMatchCUDAMode(getLangOpts(), getCurFunctionDecl())) + Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; + break; + case SC_Static: + case SC_Extern: + case SC_PrivateExtern: + break; + } + } else if (SC == SC_Register) { + // Global Named register + if (DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) { + const auto &TI = Context.getTargetInfo(); + bool HasSizeMismatch; + + if (!TI.isValidGCCRegisterName(Label)) + Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; + else if (!TI.validateGlobalRegisterVariable(Label, Context.getTypeSize(R), + HasSizeMismatch)) + Diag(E->getExprLoc(), diag::err_asm_invalid_global_var_reg) << Label; + else if (HasSizeMismatch) + Diag(E->getExprLoc(), diag::err_asm_register_size_mismatch) << Label; + } + + if (!R->isIntegralType(Context) && !R->isPointerType()) { + Diag(TInfo->getTypeLoc().getBeginLoc(), + diag::err_asm_unsupported_register_type) + << TInfo->getTypeLoc().getSourceRange(); + NewVD->setInvalidDecl(true); + } + } +} + NamedDecl *Sema::ActOnVariableDeclarator( Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, @@ -8124,6 +8176,26 @@ NamedDecl *Sema::ActOnVariableDeclarator( } } + if (Expr *E = D.getAsmLabel()) { + // The parser guarantees this is a string. + StringLiteral *SE = cast<StringLiteral>(E); + StringRef Label = SE->getString(); + + // Insert the asm attribute. + NewVD->addAttr(AsmLabelAttr::Create(Context, Label, SE->getStrTokenLoc(0))); + } else if (!ExtnameUndeclaredIdentifiers.empty()) { + llvm::DenseMap<IdentifierInfo *, AsmLabelAttr *>::iterator I = + ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier()); + if (I != ExtnameUndeclaredIdentifiers.end()) { + if (isDeclExternC(NewVD)) { + NewVD->addAttr(I->second); + ExtnameUndeclaredIdentifiers.erase(I); + } else + Diag(NewVD->getLocation(), diag::warn_redefine_extname_not_applied) + << /*Variable*/ 1 << NewVD; + } + } + // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewVD, D); @@ -8174,65 +8246,11 @@ NamedDecl *Sema::ActOnVariableDeclarator( if (getLangOpts().ObjCAutoRefCount && ObjC().inferObjCARCLifetime(NewVD)) NewVD->setInvalidDecl(); - // Handle GNU asm-label extension (encoded as an attribute). - if (Expr *E = D.getAsmLabel()) { - // The parser guarantees this is a string. - StringLiteral *SE = cast<StringLiteral>(E); - StringRef Label = SE->getString(); - if (S->getFnParent() != nullptr) { - switch (SC) { - case SC_None: - case SC_Auto: - Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label; - break; - case SC_Register: - // Local Named register - if (!Context.getTargetInfo().isValidGCCRegisterName(Label) && - DeclAttrsMatchCUDAMode(getLangOpts(), getCurFunctionDecl())) - Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; - break; - case SC_Static: - case SC_Extern: - case SC_PrivateExtern: - break; - } - } else if (SC == SC_Register) { - // Global Named register - if (DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) { - const auto &TI = Context.getTargetInfo(); - bool HasSizeMismatch; - - if (!TI.isValidGCCRegisterName(Label)) - Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; - else if (!TI.validateGlobalRegisterVariable(Label, - Context.getTypeSize(R), - HasSizeMismatch)) - Diag(E->getExprLoc(), diag::err_asm_invalid_global_var_reg) << Label; - else if (HasSizeMismatch) - Diag(E->getExprLoc(), diag::err_asm_register_size_mismatch) << Label; - } - - if (!R->isIntegralType(Context) && !R->isPointerType()) { - Diag(TInfo->getTypeLoc().getBeginLoc(), - diag::err_asm_unsupported_register_type) - << TInfo->getTypeLoc().getSourceRange(); - NewVD->setInvalidDecl(true); - } - } - - NewVD->addAttr(AsmLabelAttr::Create(Context, Label, SE->getStrTokenLoc(0))); - } else if (!ExtnameUndeclaredIdentifiers.empty()) { - llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I = - ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier()); - if (I != ExtnameUndeclaredIdentifiers.end()) { - if (isDeclExternC(NewVD)) { - NewVD->addAttr(I->second); - ExtnameUndeclaredIdentifiers.erase(I); - } else - Diag(NewVD->getLocation(), diag::warn_redefine_extname_not_applied) - << /*Variable*/1 << NewVD; - } - } + // Check the ASM label here, as we need to know all other attributes of the + // Decl first. Otherwise, we can't know if the asm label refers to the + // host or device in a CUDA context. The device has other registers than + // host and we must know where the function will be placed. + CheckAsmLabel(S, D.getAsmLabel(), SC, TInfo, NewVD); // Find the shadowed declaration before filtering for scope. NamedDecl *ShadowedDecl = D.getCXXScopeSpec().isEmpty() diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index dca9d6e..a50c276 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -12811,7 +12811,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(DC)) { if (CTSD->isInStdNamespace() && llvm::StringSwitch<bool>(CTSD->getName()) - .Cases("less", "less_equal", "greater", "greater_equal", true) + .Cases({"less", "less_equal", "greater", "greater_equal"}, true) .Default(false)) { if (RHSType->isNullPtrType()) RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index f7974eb..7debe33 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -672,11 +672,12 @@ ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc, IsInStd = true; } - if (IsInStd && llvm::StringSwitch<bool>(R->getName()) - .Cases("basic_string", "deque", "forward_list", true) - .Cases("list", "map", "multimap", "multiset", true) - .Cases("priority_queue", "queue", "set", "stack", true) - .Cases("unordered_map", "unordered_set", "vector", true) + if (IsInStd && + llvm::StringSwitch<bool>(R->getName()) + .Cases({"basic_string", "deque", "forward_list"}, true) + .Cases({"list", "map", "multimap", "multiset"}, true) + .Cases({"priority_queue", "queue", "set", "stack"}, true) + .Cases({"unordered_map", "unordered_set", "vector"}, true) .Default(false)) { InitSeq.InitializeFrom( SemaRef, Entity, diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index ca99834..3bb8080 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -2996,6 +2996,8 @@ bool SemaOpenACC::CreateReductionCombinerRecipe( case OpenACCReductionOperator::Max: case OpenACCReductionOperator::Min: + BinOp = BinaryOperatorKind::BO_LT; + break; case OpenACCReductionOperator::And: case OpenACCReductionOperator::Or: // We just want a 'NYI' error in the backend, so leave an empty combiner @@ -3011,26 +3013,80 @@ bool SemaOpenACC::CreateReductionCombinerRecipe( assert(!VarTy->isArrayType() && "Only 1 level of array allowed"); + enum class CombinerFailureKind { + None = 0, + BinOp = 1, + Conditional = 2, + Assignment = 3, + }; + + auto genCombiner = [&, this](DeclRefExpr *LHSDRE, DeclRefExpr *RHSDRE) + -> std::pair<ExprResult, CombinerFailureKind> { + ExprResult BinOpRes = + SemaRef.BuildBinOp(SemaRef.getCurScope(), Loc, BinOp, LHSDRE, RHSDRE, + /*ForFoldExpr=*/false); + switch (ReductionOperator) { + case OpenACCReductionOperator::Addition: + case OpenACCReductionOperator::Multiplication: + case OpenACCReductionOperator::BitwiseAnd: + case OpenACCReductionOperator::BitwiseOr: + case OpenACCReductionOperator::BitwiseXOr: + // These 5 are simple and are being done as compound operators, so we can + // immediately quit here. + return {BinOpRes, BinOpRes.isUsable() ? CombinerFailureKind::None + : CombinerFailureKind::BinOp}; + case OpenACCReductionOperator::Max: + case OpenACCReductionOperator::Min: { + // These are done as: + // LHS = (LHS < RHS) ? LHS : RHS; and LHS = (LHS < RHS) ? RHS : LHS; + // + // The BinOpRes should have been created with the less-than, so we just + // have to build the conditional and assignment. + if (!BinOpRes.isUsable()) + return {BinOpRes, CombinerFailureKind::BinOp}; + + // Create the correct conditional operator, swapping the results + // (true/false value) depending on min/max. + ExprResult CondRes; + if (ReductionOperator == OpenACCReductionOperator::Min) + CondRes = SemaRef.ActOnConditionalOp(Loc, Loc, BinOpRes.get(), LHSDRE, + RHSDRE); + else + CondRes = SemaRef.ActOnConditionalOp(Loc, Loc, BinOpRes.get(), RHSDRE, + LHSDRE); + + if (!CondRes.isUsable()) + return {CondRes, CombinerFailureKind::Conditional}; + + // Build assignment. + ExprResult Assignment = SemaRef.BuildBinOp(SemaRef.getCurScope(), Loc, + BinaryOperatorKind::BO_Assign, + LHSDRE, CondRes.get(), + /*ForFoldExpr=*/false); + return {Assignment, Assignment.isUsable() + ? CombinerFailureKind::None + : CombinerFailureKind::Assignment}; + } + case OpenACCReductionOperator::And: + case OpenACCReductionOperator::Or: + llvm_unreachable("And/Or not implemented, but should fail earlier"); + case OpenACCReductionOperator::Invalid: + llvm_unreachable("Invalid should have been caught above"); + } + }; + auto tryCombiner = [&, this](DeclRefExpr *LHSDRE, DeclRefExpr *RHSDRE, bool IncludeTrap) { - // TODO: OpenACC: we have to figure out based on the bin-op how to do the - // ones that we can't just use compound operators for. So &&, ||, max, and - // min aren't really clear what we could do here. if (IncludeTrap) { // Trap all of the errors here, we'll emit our own at the end. Sema::TentativeAnalysisScope Trap{SemaRef}; - - return SemaRef.BuildBinOp(SemaRef.getCurScope(), Loc, BinOp, LHSDRE, - RHSDRE, - /*ForFoldExpr=*/false); - } else { - return SemaRef.BuildBinOp(SemaRef.getCurScope(), Loc, BinOp, LHSDRE, - RHSDRE, - /*ForFoldExpr=*/false); + return genCombiner(LHSDRE, RHSDRE); } + return genCombiner(LHSDRE, RHSDRE); }; struct CombinerAttemptTy { + CombinerFailureKind FailKind; VarDecl *LHS; DeclRefExpr *LHSDRE; VarDecl *RHS; @@ -3058,9 +3114,11 @@ bool SemaOpenACC::CreateReductionCombinerRecipe( RHSDecl->getBeginLoc()}, Ty, clang::VK_LValue, RHSDecl, nullptr, NOUR_None); - ExprResult BinOpResult = tryCombiner(LHSDRE, RHSDRE, /*IncludeTrap=*/true); + std::pair<ExprResult, CombinerFailureKind> BinOpResult = + tryCombiner(LHSDRE, RHSDRE, /*IncludeTrap=*/true); - return {LHSDecl, LHSDRE, RHSDecl, RHSDRE, BinOpResult.get()}; + return {BinOpResult.second, LHSDecl, LHSDRE, RHSDecl, RHSDRE, + BinOpResult.first.get()}; }; CombinerAttemptTy TopLevelCombinerInfo = formCombiner(VarTy); @@ -3081,12 +3139,20 @@ bool SemaOpenACC::CreateReductionCombinerRecipe( } } + auto EmitFailureNote = [&](CombinerFailureKind CFK) { + if (CFK == CombinerFailureKind::BinOp) + return Diag(Loc, diag::note_acc_reduction_combiner_forming) + << CFK << BinaryOperator::getOpcodeStr(BinOp); + return Diag(Loc, diag::note_acc_reduction_combiner_forming) << CFK; + }; + // Since the 'root' level didn't fail, the only thing that could be successful // is a struct that we decompose on its individual fields. RecordDecl *RD = VarTy->getAsRecordDecl(); if (!RD) { Diag(Loc, diag::err_acc_reduction_recipe_no_op) << VarTy; + EmitFailureNote(TopLevelCombinerInfo.FailKind); tryCombiner(TopLevelCombinerInfo.LHSDRE, TopLevelCombinerInfo.RHSDRE, /*IncludeTrap=*/false); return true; @@ -3098,6 +3164,7 @@ bool SemaOpenACC::CreateReductionCombinerRecipe( if (!FieldCombinerInfo.Op || FieldCombinerInfo.Op->containsErrors()) { Diag(Loc, diag::err_acc_reduction_recipe_no_op) << FD->getType(); Diag(FD->getBeginLoc(), diag::note_acc_reduction_recipe_noop_field) << RD; + EmitFailureNote(FieldCombinerInfo.FailKind); tryCombiner(FieldCombinerInfo.LHSDRE, FieldCombinerInfo.RHSDRE, /*IncludeTrap=*/false); return true; diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp index 3ba93ff9..c5ef0d5 100644 --- a/clang/lib/Sema/SemaRISCV.cpp +++ b/clang/lib/Sema/SemaRISCV.cpp @@ -1464,7 +1464,8 @@ void SemaRISCV::checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D, } else if (Info.ElementType->isBFloat16Type() && !FeatureMap.lookup("zvfbfmin") && - !FeatureMap.lookup("xandesvbfhcvt")) + !FeatureMap.lookup("xandesvbfhcvt") && + !FeatureMap.lookup("experimental-zvfbfa")) if (DeclareAndesVectorBuiltins) { Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zvfbfmin or xandesvbfhcvt"; diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 50acc83..27fd556 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -81,7 +81,7 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A, StringRef PragmaName = llvm::StringSwitch<StringRef>( PragmaNameLoc->getIdentifierInfo()->getName()) - .Cases("unroll", "nounroll", "unroll_and_jam", "nounroll_and_jam", + .Cases({"unroll", "nounroll", "unroll_and_jam", "nounroll_and_jam"}, PragmaNameLoc->getIdentifierInfo()->getName()) .Default("clang loop"); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index ca7e3b2..7f85805 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -639,15 +639,8 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( } Invalid = SemaRef.pushCodeSynthesisContext(Inst); - if (!Invalid) { - AlreadyInstantiating = - !Inst.Entity - ? false - : !SemaRef.InstantiatingSpecializations - .insert({Inst.Entity->getCanonicalDecl(), Inst.Kind}) - .second; + if (!Invalid) atTemplateBegin(SemaRef.TemplateInstCallbacks, SemaRef, Inst); - } } Sema::InstantiatingTemplate::InstantiatingTemplate( @@ -902,13 +895,6 @@ void Sema::popCodeSynthesisContext() { void Sema::InstantiatingTemplate::Clear() { if (!Invalid) { - if (!AlreadyInstantiating) { - auto &Active = SemaRef.CodeSynthesisContexts.back(); - if (Active.Entity) - SemaRef.InstantiatingSpecializations.erase( - {Active.Entity->getCanonicalDecl(), Active.Kind}); - } - atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, SemaRef.CodeSynthesisContexts.back()); @@ -2864,9 +2850,9 @@ TemplateInstantiator::TransformNestedRequirement( TemplateArgs, Constraint->getSourceRange(), Satisfaction, /*TopLevelConceptId=*/nullptr, &NewConstraint); - assert(!Success || !Trap.hasErrorOccurred() && - "Substitution failures must be handled " - "by CheckConstraintSatisfaction."); + assert((!Success || !Trap.hasErrorOccurred()) && + "Substitution failures must be handled " + "by CheckConstraintSatisfaction."); } if (!Success || Satisfaction.HasSubstitutionFailure()) @@ -3312,17 +3298,20 @@ bool Sema::SubstDefaultArgument( FunctionDecl *FD = cast<FunctionDecl>(Param->getDeclContext()); Expr *PatternExpr = Param->getUninstantiatedDefaultArg(); + RecursiveInstGuard AlreadyInstantiating( + *this, Param, RecursiveInstGuard::Kind::DefaultArgument); + if (AlreadyInstantiating) { + Param->setInvalidDecl(); + return Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) + << FD << PatternExpr->getSourceRange(); + } + EnterExpressionEvaluationContext EvalContext( *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); InstantiatingTemplate Inst(*this, Loc, Param, TemplateArgs.getInnermost()); if (Inst.isInvalid()) return true; - if (Inst.isAlreadyInstantiating()) { - Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD; - Param->setInvalidDecl(); - return true; - } ExprResult Result; // C++ [dcl.fct.default]p5: @@ -3554,12 +3543,26 @@ namespace clang { } } -bool -Sema::InstantiateClass(SourceLocation PointOfInstantiation, - CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, - const MultiLevelTemplateArgumentList &TemplateArgs, - TemplateSpecializationKind TSK, - bool Complain) { +bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, + CXXRecordDecl *Instantiation, + CXXRecordDecl *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK, bool Complain) { +#ifndef NDEBUG + RecursiveInstGuard AlreadyInstantiating(*this, Instantiation, + RecursiveInstGuard::Kind::Template); + assert(!AlreadyInstantiating && "should have been caught by caller"); +#endif + + return InstantiateClassImpl(PointOfInstantiation, Instantiation, Pattern, + TemplateArgs, TSK, Complain); +} + +bool Sema::InstantiateClassImpl( + SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, + CXXRecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK, bool Complain) { + CXXRecordDecl *PatternDef = cast_or_null<CXXRecordDecl>(Pattern->getDefinition()); if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Instantiation, @@ -3596,7 +3599,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst.isInvalid()) return true; - assert(!Inst.isAlreadyInstantiating() && "should have been caught by caller"); PrettyDeclStackTraceEntry CrashInfo(Context, Instantiation, SourceLocation(), "instantiating class definition"); @@ -3808,6 +3810,12 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation, EnumDecl *Instantiation, EnumDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK) { +#ifndef NDEBUG + RecursiveInstGuard AlreadyInstantiating(*this, Instantiation, + RecursiveInstGuard::Kind::Template); + assert(!AlreadyInstantiating && "should have been caught by caller"); +#endif + EnumDecl *PatternDef = Pattern->getDefinition(); if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Instantiation, Instantiation->getInstantiatedFromMemberEnum(), @@ -3825,8 +3833,6 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst.isInvalid()) return true; - if (Inst.isAlreadyInstantiating()) - return false; PrettyDeclStackTraceEntry CrashInfo(Context, Instantiation, SourceLocation(), "instantiating enum definition"); @@ -3865,6 +3871,14 @@ bool Sema::InstantiateInClassInitializer( Pattern->getInClassInitStyle() && "pattern and instantiation disagree about init style"); + RecursiveInstGuard AlreadyInstantiating(*this, Instantiation, + RecursiveInstGuard::Kind::Template); + if (AlreadyInstantiating) + // Error out if we hit an instantiation cycle for this initializer. + return Diag(PointOfInstantiation, + diag::err_default_member_initializer_cycle) + << Instantiation; + // Error out if we haven't parsed the initializer of the pattern yet because // we are waiting for the closing brace of the outer class. Expr *OldInit = Pattern->getInClassInitializer(); @@ -3883,12 +3897,6 @@ bool Sema::InstantiateInClassInitializer( InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst.isInvalid()) return true; - if (Inst.isAlreadyInstantiating()) { - // Error out if we hit an instantiation cycle for this initializer. - Diag(PointOfInstantiation, diag::err_default_member_initializer_cycle) - << Instantiation; - return true; - } PrettyDeclStackTraceEntry CrashInfo(Context, Instantiation, SourceLocation(), "instantiating default member init"); @@ -3972,8 +3980,6 @@ static ActionResult<CXXRecordDecl *> getPatternForClassTemplateSpecialization( Sema::InstantiatingTemplate Inst(S, PointOfInstantiation, ClassTemplateSpec); if (Inst.isInvalid()) return {/*Invalid=*/true}; - if (Inst.isAlreadyInstantiating()) - return {/*Invalid=*/false}; llvm::PointerUnion<ClassTemplateDecl *, ClassTemplatePartialSpecializationDecl *> @@ -4136,6 +4142,11 @@ bool Sema::InstantiateClassTemplateSpecialization( if (ClassTemplateSpec->isInvalidDecl()) return true; + Sema::RecursiveInstGuard AlreadyInstantiating( + *this, ClassTemplateSpec, Sema::RecursiveInstGuard::Kind::Template); + if (AlreadyInstantiating) + return false; + bool HadAvaibilityWarning = ShouldDiagnoseAvailabilityOfDecl(ClassTemplateSpec, nullptr, nullptr) .first != AR_Available; @@ -4148,7 +4159,7 @@ bool Sema::InstantiateClassTemplateSpecialization( if (!Pattern.isUsable()) return Pattern.isInvalid(); - bool Err = InstantiateClass( + bool Err = InstantiateClassImpl( PointOfInstantiation, ClassTemplateSpec, Pattern.get(), getTemplateInstantiationArgs(ClassTemplateSpec), TSK, Complain); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 4863b45..28925cc 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -5312,6 +5312,16 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, if (Proto->getExceptionSpecType() != EST_Uninstantiated) return; + RecursiveInstGuard AlreadyInstantiating( + *this, Decl, RecursiveInstGuard::Kind::ExceptionSpec); + if (AlreadyInstantiating) { + // This exception specification indirectly depends on itself. Reject. + // FIXME: Corresponding rule in the standard? + Diag(PointOfInstantiation, diag::err_exception_spec_cycle) << Decl; + UpdateExceptionSpec(Decl, EST_None); + return; + } + InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl, InstantiatingTemplate::ExceptionSpecification()); if (Inst.isInvalid()) { @@ -5320,13 +5330,6 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, UpdateExceptionSpec(Decl, EST_None); return; } - if (Inst.isAlreadyInstantiating()) { - // This exception specification indirectly depends on itself. Reject. - // FIXME: Corresponding rule in the standard? - Diag(PointOfInstantiation, diag::err_exception_spec_cycle) << Decl; - UpdateExceptionSpec(Decl, EST_None); - return; - } // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. @@ -5386,8 +5389,6 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution || ActiveInst.Kind == ActiveInstType::DeducedTemplateArgumentSubstitution) { if (isa<FunctionTemplateDecl>(ActiveInst.Entity)) { - SemaRef.InstantiatingSpecializations.erase( - {ActiveInst.Entity->getCanonicalDecl(), ActiveInst.Kind}); atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, ActiveInst); ActiveInst.Kind = ActiveInstType::TemplateInstantiation; ActiveInst.Entity = New; @@ -5545,6 +5546,12 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, Function = const_cast<FunctionDecl*>(ExistingDefn); } +#ifndef NDEBUG + RecursiveInstGuard AlreadyInstantiating(*this, Function, + RecursiveInstGuard::Kind::Template); + assert(!AlreadyInstantiating && "should have been caught by caller"); +#endif + // Find the function body that we'll be substituting. const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern(); assert(PatternDecl && "instantiating a non-template"); @@ -5684,7 +5691,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, } InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); - if (Inst.isInvalid() || Inst.isAlreadyInstantiating()) + if (Inst.isInvalid()) return; PrettyDeclStackTraceEntry CrashInfo(Context, Function, SourceLocation(), "instantiating function definition"); @@ -6253,6 +6260,11 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, if (TSK == TSK_ExplicitSpecialization) return; + RecursiveInstGuard AlreadyInstantiating(*this, Var, + RecursiveInstGuard::Kind::Template); + if (AlreadyInstantiating) + return; + // Find the pattern and the arguments to substitute into it. VarDecl *PatternDecl = Var->getTemplateInstantiationPattern(); assert(PatternDecl && "no pattern for templated variable"); @@ -6276,7 +6288,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, // FIXME: Factor out the duplicated instantiation context setup/tear down // code here. InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); - if (Inst.isInvalid() || Inst.isAlreadyInstantiating()) + if (Inst.isInvalid()) return; PrettyDeclStackTraceEntry CrashInfo(Context, Var, SourceLocation(), "instantiating variable initializer"); @@ -6380,7 +6392,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, } InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); - if (Inst.isInvalid() || Inst.isAlreadyInstantiating()) + if (Inst.isInvalid()) return; PrettyDeclStackTraceEntry CrashInfo(Context, Var, SourceLocation(), "instantiating variable definition"); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 29f0c30..0c8c1d1 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -16430,12 +16430,16 @@ ExprResult TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr( AssociatedDecl == E->getAssociatedDecl()) return E; - auto getParamAndType = [Index = E->getIndex()](Decl *AssociatedDecl) + auto getParamAndType = [E](Decl *AssociatedDecl) -> std::tuple<NonTypeTemplateParmDecl *, QualType> { - auto [PDecl, Arg] = getReplacedTemplateParameter(AssociatedDecl, Index); + auto [PDecl, Arg] = + getReplacedTemplateParameter(AssociatedDecl, E->getIndex()); auto *Param = cast<NonTypeTemplateParmDecl>(PDecl); - return {Param, Arg.isNull() ? Param->getType() - : Arg.getNonTypeTemplateArgumentType()}; + if (Arg.isNull()) + return {Param, Param->getType()}; + if (UnsignedOrNone PackIndex = E->getPackIndex()) + Arg = Arg.getPackAsArray()[*PackIndex]; + return {Param, Arg.getNonTypeTemplateArgumentType()}; }; // If the replacement expression did not change, and the parameter type |