summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaConcept.cpp
diff options
context:
space:
mode:
authorVedant Kumar <vsk@apple.com>2019-12-18 14:52:51 -0800
committerVedant Kumar <vsk@apple.com>2019-12-18 15:02:39 -0800
commit5094e6dad64c755be1bb797b0307c54dbae8871d (patch)
treee69dc554593934e48240b90458911b6098ae0862 /clang/lib/Sema/SemaConcept.cpp
parentf0df4218b67d0abe96867804b8932b9b88998f51 (diff)
downloadbcm5719-llvm-5094e6dad64c755be1bb797b0307c54dbae8871d.tar.gz
bcm5719-llvm-5094e6dad64c755be1bb797b0307c54dbae8871d.zip
Revert concepts changes from D41910
These changes caused LibcxxVariantDataFormatterTestCase in lldb to fail with an assert: Assertion failed: (Idx < size() && "Out-of-bounds Bit access."), function operator[], file /Users/buildslave/jenkins/workspace/lldb-cmake/llvm-project/llvm/include/llvm/ADT/SmallBitVector.h, line 452. In: 7 clang-10 0x00000001094b79d9 isAtLeastAsSpecializedAs(clang::Sema&, clang::SourceLocation, clang::FunctionTemplateDecl*, clang::FunctionTemplateDecl*, clang::TemplatePartialOrderingContext, unsigned int) + 1865 8 clang-10 0x00000001094b7111 clang::Sema::getMoreSpecializedTemplate(clang::FunctionTemplateDecl*, clang::FunctionTemplateDecl*, clang::SourceLocation, clang::TemplatePartialOrderingContext, unsigned int, unsigned int) + 97 9 clang-10 0x000000010939bf88 clang::isBetterOverloadCandidate(clang::Sema&, clang::OverloadCandidate const&, clang::OverloadCandidate const&, clang::SourceLocation, clang::OverloadCandidateSet::CandidateSetKind) + 1128 Revert "[Concepts] Fix incorrect move out of temporary in D41910" This reverts commit 11d5fa6e87e3584f72056ecc2b17f88c58323dde. Revert "[Concepts] Fix crash in D41910" This reverts commit 12038be20ee6a903cdbd3fddce65535ef683e31d. Revert "[Concepts] Constrained partial specializations and function overloads." This reverts commit fc0731b98a67c793862288f8ae334322666214dc.
Diffstat (limited to 'clang/lib/Sema/SemaConcept.cpp')
-rw-r--r--[-rwxr-xr-x]clang/lib/Sema/SemaConcept.cpp360
1 files changed, 0 insertions, 360 deletions
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 63b8e06a7ae..f917d9c7e5a 100755..100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -17,7 +17,6 @@
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/Template.h"
#include "clang/AST/ExprCXX.h"
-#include "clang/AST/RecursiveASTVisitor.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerUnion.h"
using namespace clang;
@@ -415,363 +414,4 @@ void Sema::DiagnoseUnsatisfiedConstraint(
diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First);
First = false;
}
-}
-
-namespace {
-struct AtomicConstraint {
- const Expr *ConstraintExpr;
- llvm::Optional<llvm::SmallVector<TemplateArgumentLoc, 3>> ParameterMapping;
-
- AtomicConstraint(Sema &S, const Expr *ConstraintExpr) :
- ConstraintExpr(ConstraintExpr) { };
-
- bool hasMatchingParameterMapping(ASTContext &C,
- const AtomicConstraint &Other) const {
- if (!ParameterMapping != !Other.ParameterMapping)
- return false;
- if (!ParameterMapping)
- return true;
- if (ParameterMapping->size() != Other.ParameterMapping->size())
- return false;
-
- for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I)
- if (!C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument())
- .structurallyEquals(C.getCanonicalTemplateArgument(
- (*Other.ParameterMapping)[I].getArgument())))
- return false;
- return true;
- }
-
- bool subsumes(ASTContext &C, const AtomicConstraint &Other) const {
- // C++ [temp.constr.order] p2
- // - an atomic constraint A subsumes another atomic constraint B
- // if and only if the A and B are identical [...]
- //
- // C++ [temp.constr.atomic] p2
- // Two atomic constraints are identical if they are formed from the
- // same expression and the targets of the parameter mappings are
- // equivalent according to the rules for expressions [...]
-
- // We do not actually substitute the parameter mappings into the
- // constraint expressions, therefore the constraint expressions are
- // the originals, and comparing them will suffice.
- if (ConstraintExpr != Other.ConstraintExpr)
- return false;
-
- // Check that the parameter lists are identical
- return hasMatchingParameterMapping(C, Other);
- }
-};
-
-/// \brief A normalized constraint, as defined in C++ [temp.constr.normal], is
-/// either an atomic constraint, a conjunction of normalized constraints or a
-/// disjunction of normalized constraints.
-struct NormalizedConstraint {
- enum CompoundConstraintKind { CCK_Conjunction, CCK_Disjunction };
-
- using CompoundConstraint = llvm::PointerIntPair<
- std::pair<NormalizedConstraint, NormalizedConstraint> *, 1,
- CompoundConstraintKind>;
-
- llvm::PointerUnion<AtomicConstraint *, CompoundConstraint> Constraint;
-
- NormalizedConstraint(AtomicConstraint *C): Constraint{C} { };
- NormalizedConstraint(ASTContext &C, NormalizedConstraint LHS,
- NormalizedConstraint RHS, CompoundConstraintKind Kind)
- : Constraint{CompoundConstraint{
- new (C) std::pair<NormalizedConstraint, NormalizedConstraint>{LHS,
- RHS},
- Kind}} { };
-
- CompoundConstraintKind getCompoundKind() const {
- assert(!isAtomic() && "getCompoundKind called on atomic constraint.");
- return Constraint.get<CompoundConstraint>().getInt();
- }
-
- bool isAtomic() const { return Constraint.is<AtomicConstraint *>(); }
-
- NormalizedConstraint &getLHS() const {
- assert(!isAtomic() && "getLHS called on atomic constraint.");
- return Constraint.get<CompoundConstraint>().getPointer()->first;
- }
-
- NormalizedConstraint &getRHS() const {
- assert(!isAtomic() && "getRHS called on atomic constraint.");
- return Constraint.get<CompoundConstraint>().getPointer()->second;
- }
-
- AtomicConstraint *getAtomicConstraint() const {
- assert(isAtomic() &&
- "getAtomicConstraint called on non-atomic constraint.");
- return Constraint.get<AtomicConstraint *>();
- }
-
- static llvm::Optional<NormalizedConstraint>
- fromConstraintExprs(Sema &S, NamedDecl *D, ArrayRef<const Expr *> E) {
- assert(E.size() != 0);
- auto First = fromConstraintExpr(S, D, E[0]);
- if (E.size() == 1)
- return First;
- auto Second = fromConstraintExpr(S, D, E[1]);
- if (!Second)
- return llvm::Optional<NormalizedConstraint>{};
- llvm::Optional<NormalizedConstraint> Conjunction;
- Conjunction.emplace(S.Context, std::move(*First), std::move(*Second),
- CCK_Conjunction);
- for (unsigned I = 2; I < E.size(); ++I) {
- auto Next = fromConstraintExpr(S, D, E[I]);
- if (!Next)
- return llvm::Optional<NormalizedConstraint>{};
- NormalizedConstraint NewConjunction(S.Context, std::move(*Conjunction),
- std::move(*Next), CCK_Conjunction);
- *Conjunction = std::move(NewConjunction);
- }
- return Conjunction;
- }
-
-private:
- static llvm::Optional<NormalizedConstraint> fromConstraintExpr(Sema &S,
- NamedDecl *D,
- const Expr *E);
-};
-
-static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
- ConceptDecl *Concept, ArrayRef<TemplateArgument> TemplateArgs,
- const ASTTemplateArgumentListInfo *ArgsAsWritten) {
- if (!N.isAtomic()) {
- if (substituteParameterMappings(S, N.getLHS(), Concept, TemplateArgs,
- ArgsAsWritten))
- return true;
- return substituteParameterMappings(S, N.getRHS(), Concept, TemplateArgs,
- ArgsAsWritten);
- }
- TemplateParameterList *TemplateParams = Concept->getTemplateParameters();
-
- AtomicConstraint &Atomic = *N.getAtomicConstraint();
- TemplateArgumentListInfo SubstArgs;
- MultiLevelTemplateArgumentList MLTAL;
- MLTAL.addOuterTemplateArguments(TemplateArgs);
- if (!Atomic.ParameterMapping) {
- llvm::SmallBitVector OccurringIndices;
- S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false,
- /*Depth=*/0, OccurringIndices);
- Atomic.ParameterMapping.emplace();
- Atomic.ParameterMapping->reserve(OccurringIndices.size());
- for (unsigned I = 0, C = TemplateParams->size(); I != C; ++I)
- if (I < OccurringIndices.size() && OccurringIndices[I])
- Atomic.ParameterMapping->push_back(
- S.getIdentityTemplateArgumentLoc(TemplateParams->begin()[I],
- // Here we assume we do not support things like
- // template<typename A, typename B>
- // concept C = ...;
- //
- // template<typename... Ts> requires C<Ts...>
- // struct S { };
- // The above currently yields a diagnostic.
- // We still might have default arguments for concept parameters.
- ArgsAsWritten->NumTemplateArgs > I ?
- ArgsAsWritten->arguments()[I].getLocation() :
- SourceLocation()));
- }
- Sema::InstantiatingTemplate Inst(
- S, ArgsAsWritten->arguments().front().getSourceRange().getBegin(),
- Sema::InstantiatingTemplate::ParameterMappingSubstitution{}, Concept,
- SourceRange(ArgsAsWritten->arguments()[0].getSourceRange().getBegin(),
- ArgsAsWritten->arguments().back().getSourceRange().getEnd()));
- if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs))
- return true;
- std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(),
- N.getAtomicConstraint()->ParameterMapping->begin());
- return false;
-}
-
-llvm::Optional<NormalizedConstraint>
-NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
- assert(E != nullptr);
-
- // C++ [temp.constr.normal]p1.1
- // [...]
- // - The normal form of an expression (E) is the normal form of E.
- // [...]
- E = E->IgnoreParenImpCasts();
- if (auto *BO = dyn_cast<const BinaryOperator>(E)) {
- if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) {
- auto LHS = fromConstraintExpr(S, D, BO->getLHS());
- if (!LHS)
- return None;
- auto RHS = fromConstraintExpr(S, D, BO->getRHS());
- if (!RHS)
- return None;
-
- return NormalizedConstraint(
- S.Context, *LHS, *RHS,
- BO->getOpcode() == BO_LAnd ? CCK_Conjunction : CCK_Disjunction);
- }
- } else if (auto *CSE = dyn_cast<const ConceptSpecializationExpr>(E)) {
- Optional<NormalizedConstraint> SubNF;
- {
- Sema::InstantiatingTemplate Inst(
- S, CSE->getExprLoc(),
- Sema::InstantiatingTemplate::ConstraintNormalization{}, D,
- CSE->getSourceRange());
- // C++ [temp.constr.normal]p1.1
- // [...]
- // The normal form of an id-expression of the form C<A1, A2, ..., AN>,
- // where C names a concept, is the normal form of the
- // constraint-expression of C, after substituting A1, A2, ..., AN for C’s
- // respective template parameters in the parameter mappings in each atomic
- // constraint. If any such substitution results in an invalid type or
- // expression, the program is ill-formed; no diagnostic is required.
- // [...]
- SubNF = fromConstraintExpr(S, CSE->getNamedConcept(),
- CSE->getNamedConcept()->getConstraintExpr());
- if (!SubNF)
- return None;
- }
-
- if (substituteParameterMappings(
- S, *SubNF, CSE->getNamedConcept(),
- CSE->getTemplateArguments(), CSE->getTemplateArgsAsWritten()))
- return None;
-
- return SubNF;
- }
- return NormalizedConstraint{new (S.Context) AtomicConstraint(S, E)};
-}
-
-} // namespace
-
-using NormalForm =
- llvm::SmallVector<llvm::SmallVector<AtomicConstraint *, 2>, 4>;
-
-static NormalForm makeCNF(const NormalizedConstraint &Normalized) {
- if (Normalized.isAtomic())
- return {{Normalized.getAtomicConstraint()}};
-
- NormalForm LCNF = makeCNF(Normalized.getLHS());
- NormalForm RCNF = makeCNF(Normalized.getRHS());
- if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Conjunction) {
- LCNF.reserve(LCNF.size() + RCNF.size());
- while (!RCNF.empty())
- LCNF.push_back(RCNF.pop_back_val());
- return LCNF;
- }
-
- // Disjunction
- NormalForm Res;
- Res.reserve(LCNF.size() * RCNF.size());
- for (auto &LDisjunction : LCNF)
- for (auto &RDisjunction : RCNF) {
- NormalForm::value_type Combined;
- Combined.reserve(LDisjunction.size() + RDisjunction.size());
- std::copy(LDisjunction.begin(), LDisjunction.end(),
- std::back_inserter(Combined));
- std::copy(RDisjunction.begin(), RDisjunction.end(),
- std::back_inserter(Combined));
- Res.emplace_back(Combined);
- }
- return Res;
-}
-
-static NormalForm makeDNF(const NormalizedConstraint &Normalized) {
- if (Normalized.isAtomic())
- return {{Normalized.getAtomicConstraint()}};
-
- NormalForm LDNF = makeDNF(Normalized.getLHS());
- NormalForm RDNF = makeDNF(Normalized.getRHS());
- if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Disjunction) {
- LDNF.reserve(LDNF.size() + RDNF.size());
- while (!RDNF.empty())
- LDNF.push_back(RDNF.pop_back_val());
- return LDNF;
- }
-
- // Conjunction
- NormalForm Res;
- Res.reserve(LDNF.size() * RDNF.size());
- for (auto &LConjunction : LDNF) {
- for (auto &RConjunction : RDNF) {
- NormalForm::value_type Combined;
- Combined.reserve(LConjunction.size() + RConjunction.size());
- std::copy(LConjunction.begin(), LConjunction.end(),
- std::back_inserter(Combined));
- std::copy(RConjunction.begin(), RConjunction.end(),
- std::back_inserter(Combined));
- Res.emplace_back(Combined);
- }
- }
- return Res;
-}
-
-static bool subsumes(Sema &S, NamedDecl *DP, ArrayRef<const Expr *> P,
- NamedDecl *DQ, ArrayRef<const Expr *> Q, bool &Subsumes) {
- // C++ [temp.constr.order] p2
- // In order to determine if a constraint P subsumes a constraint Q, P is
- // transformed into disjunctive normal form, and Q is transformed into
- // conjunctive normal form. [...]
- auto PNormalized = NormalizedConstraint::fromConstraintExprs(S, DP, P);
- if (!PNormalized)
- return true;
- const NormalForm PDNF = makeDNF(*PNormalized);
-
- auto QNormalized = NormalizedConstraint::fromConstraintExprs(S, DQ, Q);
- if (!QNormalized)
- return true;
- const NormalForm QCNF = makeCNF(*QNormalized);
-
- // C++ [temp.constr.order] p2
- // Then, P subsumes Q if and only if, for every disjunctive clause Pi in the
- // disjunctive normal form of P, Pi subsumes every conjunctive clause Qj in
- // the conjuctive normal form of Q, where [...]
- for (const auto &Pi : PDNF) {
- for (const auto &Qj : QCNF) {
- // C++ [temp.constr.order] p2
- // - [...] a disjunctive clause Pi subsumes a conjunctive clause Qj if
- // and only if there exists an atomic constraint Pia in Pi for which
- // there exists an atomic constraint, Qjb, in Qj such that Pia
- // subsumes Qjb.
- bool Found = false;
- for (const AtomicConstraint *Pia : Pi) {
- for (const AtomicConstraint *Qjb : Qj) {
- if (Pia->subsumes(S.Context, *Qjb)) {
- Found = true;
- break;
- }
- }
- if (Found)
- break;
- }
- if (!Found) {
- Subsumes = false;
- return false;
- }
- }
- }
- Subsumes = true;
- return false;
-}
-
-bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef<const Expr *> AC1,
- NamedDecl *D2, ArrayRef<const Expr *> AC2,
- bool &Result) {
- if (AC1.empty()) {
- Result = AC2.empty();
- return false;
- }
- if (AC2.empty()) {
- // TD1 has associated constraints and TD2 does not.
- Result = true;
- return false;
- }
-
- std::pair<NamedDecl *, NamedDecl *> Key{D1, D2};
- auto CacheEntry = SubsumptionCache.find(Key);
- if (CacheEntry != SubsumptionCache.end()) {
- Result = CacheEntry->second;
- return false;
- }
- if (subsumes(*this, D1, AC1, D2, AC2, Result))
- return true;
- SubsumptionCache.try_emplace(Key, Result);
- return false;
} \ No newline at end of file
OpenPOWER on IntegriCloud