aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/SemaChecking.cpp12
-rw-r--r--clang/lib/Sema/SemaConcept.cpp44
-rw-r--r--clang/lib/Sema/SemaExpr.cpp2
-rw-r--r--clang/lib/Sema/SemaInit.cpp11
-rw-r--r--clang/lib/Sema/SemaOpenACC.cpp93
-rw-r--r--clang/lib/Sema/SemaStmtAttr.cpp2
6 files changed, 124 insertions, 40 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ef1be23..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)
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 829bd87..54cbfe4 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -570,6 +570,11 @@ ConstraintSatisfactionChecker::SubstitutionInTemplateArguments(
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(),
@@ -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)});
@@ -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;
@@ -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/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/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");