aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/ASTConcept.cpp2
-rw-r--r--clang/lib/AST/ByteCode/Program.cpp5
-rw-r--r--clang/lib/Analysis/ExprMutationAnalyzer.cpp20
-rw-r--r--clang/lib/Format/WhitespaceManager.cpp118
-rw-r--r--clang/lib/Sema/SemaConcept.cpp44
5 files changed, 83 insertions, 106 deletions
diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp
index fd12bc4..9ea104c 100644
--- a/clang/lib/AST/ASTConcept.cpp
+++ b/clang/lib/AST/ASTConcept.cpp
@@ -86,7 +86,7 @@ void ConstraintSatisfaction::Profile(llvm::FoldingSetNodeID &ID,
ID.AddPointer(ConstraintOwner);
ID.AddInteger(TemplateArgs.size());
for (auto &Arg : TemplateArgs)
- Arg.Profile(ID, C);
+ C.getCanonicalTemplateArgument(Arg).Profile(ID, C);
}
ConceptReference *
diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp
index e653782..e0b2852 100644
--- a/clang/lib/AST/ByteCode/Program.cpp
+++ b/clang/lib/AST/ByteCode/Program.cpp
@@ -226,7 +226,10 @@ UnsignedOrNone Program::createGlobal(const ValueDecl *VD, const Expr *Init) {
Globals[PIdx] = NewGlobal;
// All pointers pointing to the previous extern decl now point to the
// new decl.
- RedeclBlock->movePointersTo(NewGlobal->block());
+ // A previous iteration might've already fixed up the pointers for this
+ // global.
+ if (RedeclBlock != NewGlobal->block())
+ RedeclBlock->movePointersTo(NewGlobal->block());
}
}
PIdx = *Idx;
diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
index 1e376da..75b17c54 100644
--- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp
+++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
@@ -140,7 +140,8 @@ class ExprPointeeResolve {
// explicit cast will be checked in `findPointeeToNonConst`
const CastKind kind = ICE->getCastKind();
if (kind == CK_LValueToRValue || kind == CK_DerivedToBase ||
- kind == CK_UncheckedDerivedToBase)
+ kind == CK_UncheckedDerivedToBase ||
+ (kind == CK_NoOp && (ICE->getType() == ICE->getSubExpr()->getType())))
return resolveExpr(ICE->getSubExpr());
return false;
}
@@ -788,13 +789,16 @@ ExprMutationAnalyzer::Analyzer::findPointeeToNonConst(const Expr *Exp) {
// FIXME: false positive if the pointee does not change in lambda
const auto CaptureNoConst = lambdaExpr(hasCaptureInit(Exp));
- const auto Matches =
- match(stmt(anyOf(forEachDescendant(
- stmt(anyOf(AssignToNonConst, PassAsNonConstArg,
- CastToNonConst, CaptureNoConst))
- .bind("stmt")),
- forEachDescendant(InitToNonConst))),
- Stm, Context);
+ const auto ReturnNoConst =
+ returnStmt(hasReturnValue(canResolveToExprPointee(Exp)));
+
+ const auto Matches = match(
+ stmt(anyOf(forEachDescendant(
+ stmt(anyOf(AssignToNonConst, PassAsNonConstArg,
+ CastToNonConst, CaptureNoConst, ReturnNoConst))
+ .bind("stmt")),
+ forEachDescendant(InitToNonConst))),
+ Stm, Context);
return selectFirst<Stmt>("stmt", Matches);
}
diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp
index 9261294..b004d73 100644
--- a/clang/lib/Format/WhitespaceManager.cpp
+++ b/clang/lib/Format/WhitespaceManager.cpp
@@ -432,7 +432,11 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End,
// right-justified. It is used to align compound assignments like `+=` and `=`.
// When RightJustify and ACS.PadOperators are true, operators in each block to
// be aligned will be padded on the left to the same length before aligning.
-template <typename F>
+//
+// The simple check will not look at the indentaion and nesting level to recurse
+// into the line for alignment. It will also not count the commas. This is e.g.
+// for aligning macro definitions.
+template <typename F, bool SimpleCheck = false>
static unsigned AlignTokens(const FormatStyle &Style, F &&Matches,
SmallVector<WhitespaceManager::Change, 16> &Changes,
unsigned StartAt,
@@ -465,9 +469,9 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches,
// Measure the scope level (i.e. depth of (), [], {}) of the first token, and
// abort when we hit any token in a higher scope than the starting one.
- auto IndentAndNestingLevel = StartAt < Changes.size()
- ? Changes[StartAt].indentAndNestingLevel()
- : std::tuple<unsigned, unsigned, unsigned>();
+ const auto IndentAndNestingLevel =
+ StartAt < Changes.size() ? Changes[StartAt].indentAndNestingLevel()
+ : std::tuple<unsigned, unsigned, unsigned>();
// Keep track of the number of commas before the matching tokens, we will only
// align a sequence of matching tokens if they are preceded by the same number
@@ -536,14 +540,17 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches,
if (CurrentChange.Tok->isNot(tok::comment))
LineIsComment = false;
- if (CurrentChange.Tok->is(tok::comma)) {
- ++CommasBeforeMatch;
- } else if (CurrentChange.indentAndNestingLevel() > IndentAndNestingLevel) {
- // Call AlignTokens recursively, skipping over this scope block.
- unsigned StoppedAt =
- AlignTokens(Style, Matches, Changes, i, ACS, RightJustify);
- i = StoppedAt - 1;
- continue;
+ if (!SimpleCheck) {
+ if (CurrentChange.Tok->is(tok::comma)) {
+ ++CommasBeforeMatch;
+ } else if (CurrentChange.indentAndNestingLevel() >
+ IndentAndNestingLevel) {
+ // Call AlignTokens recursively, skipping over this scope block.
+ const auto StoppedAt =
+ AlignTokens(Style, Matches, Changes, i, ACS, RightJustify);
+ i = StoppedAt - 1;
+ continue;
+ }
}
if (!Matches(CurrentChange))
@@ -656,7 +663,7 @@ void WhitespaceManager::alignConsecutiveMacros() {
auto AlignMacrosMatches = [](const Change &C) {
const FormatToken *Current = C.Tok;
- unsigned SpacesRequiredBefore = 1;
+ assert(Current);
if (Current->SpacesRequiredBefore == 0 || !Current->Previous)
return false;
@@ -665,79 +672,26 @@ void WhitespaceManager::alignConsecutiveMacros() {
// If token is a ")", skip over the parameter list, to the
// token that precedes the "("
- if (Current->is(tok::r_paren) && Current->MatchingParen) {
- Current = Current->MatchingParen->Previous;
- SpacesRequiredBefore = 0;
- }
-
- if (!Current || Current->isNot(tok::identifier))
- return false;
-
- if (!Current->Previous || Current->Previous->isNot(tok::pp_define))
- return false;
-
- // For a macro function, 0 spaces are required between the
- // identifier and the lparen that opens the parameter list.
- // For a simple macro, 1 space is required between the
- // identifier and the first token of the defined value.
- return Current->Next->SpacesRequiredBefore == SpacesRequiredBefore;
- };
-
- unsigned MinColumn = 0;
-
- // Start and end of the token sequence we're processing.
- unsigned StartOfSequence = 0;
- unsigned EndOfSequence = 0;
-
- // Whether a matching token has been found on the current line.
- bool FoundMatchOnLine = false;
-
- // Whether the current line consists only of comments
- bool LineIsComment = true;
-
- unsigned I = 0;
- for (unsigned E = Changes.size(); I != E; ++I) {
- if (Changes[I].NewlinesBefore != 0) {
- EndOfSequence = I;
-
- // Whether to break the alignment sequence because of an empty line.
- bool EmptyLineBreak = (Changes[I].NewlinesBefore > 1) &&
- !Style.AlignConsecutiveMacros.AcrossEmptyLines;
-
- // Whether to break the alignment sequence because of a line without a
- // match.
- bool NoMatchBreak =
- !FoundMatchOnLine &&
- !(LineIsComment && Style.AlignConsecutiveMacros.AcrossComments);
-
- if (EmptyLineBreak || NoMatchBreak) {
- AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn,
- AlignMacrosMatches, Changes);
+ if (Current->is(tok::r_paren)) {
+ const auto *MatchingParen = Current->MatchingParen;
+ // For a macro function, 0 spaces are required between the
+ // identifier and the lparen that opens the parameter list.
+ if (!MatchingParen || MatchingParen->SpacesRequiredBefore > 0 ||
+ !MatchingParen->Previous) {
+ return false;
}
-
- // A new line starts, re-initialize line status tracking bools.
- FoundMatchOnLine = false;
- LineIsComment = true;
+ Current = MatchingParen->Previous;
+ } else if (Current->Next->SpacesRequiredBefore != 1) {
+ // For a simple macro, 1 space is required between the
+ // identifier and the first token of the defined value.
+ return false;
}
- if (Changes[I].Tok->isNot(tok::comment))
- LineIsComment = false;
-
- if (!AlignMacrosMatches(Changes[I]))
- continue;
-
- FoundMatchOnLine = true;
-
- if (StartOfSequence == 0)
- StartOfSequence = I;
-
- unsigned ChangeMinColumn = Changes[I].StartOfTokenColumn;
- MinColumn = std::max(MinColumn, ChangeMinColumn);
- }
+ return Current->endsSequence(tok::identifier, tok::pp_define);
+ };
- EndOfSequence = I;
- AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn,
- AlignMacrosMatches, Changes);
+ AlignTokens<decltype(AlignMacrosMatches) &, /*SimpleCheck=*/true>(
+ Style, AlignMacrosMatches, Changes, 0, Style.AlignConsecutiveMacros);
}
void WhitespaceManager::alignConsecutiveAssignments() {
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;