blob: d0526f4fa5c592c8a77cb89c23d8222d45bf049b [file] [log] [blame]
//===--- ASTConcept.h - Concepts Related AST Data Structures ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief This file provides AST data structures related to concepts.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_ASTCONCEPT_H
#define LLVM_CLANG_AST_ASTCONCEPT_H
#include "clang/AST/Expr.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallVector.h"
#include <utility>
namespace clang {
class ConceptDecl;
class ConceptSpecializationExpr;
/// The result of a constraint satisfaction check, containing the necessary
/// information to diagnose an unsatisfied constraint.
class ConstraintSatisfaction : public llvm::FoldingSetNode {
// The template-like entity that 'owns' the constraint checked here (can be a
// constrained entity or a concept).
const NamedDecl *ConstraintOwner = nullptr;
llvm::SmallVector<TemplateArgument, 4> TemplateArgs;
public:
ConstraintSatisfaction() = default;
ConstraintSatisfaction(const NamedDecl *ConstraintOwner,
ArrayRef<TemplateArgument> TemplateArgs) :
ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs.begin(),
TemplateArgs.end()) { }
using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
using Detail = llvm::PointerUnion<Expr *, SubstitutionDiagnostic *>;
bool IsSatisfied = false;
/// \brief Pairs of unsatisfied atomic constraint expressions along with the
/// substituted constraint expr, if the template arguments could be
/// substituted into them, or a diagnostic if substitution resulted in an
/// invalid expression.
llvm::SmallVector<std::pair<const Expr *, Detail>, 4> Details;
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C) {
Profile(ID, C, ConstraintOwner, TemplateArgs);
}
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C,
const NamedDecl *ConstraintOwner,
ArrayRef<TemplateArgument> TemplateArgs);
};
/// Pairs of unsatisfied atomic constraint expressions along with the
/// substituted constraint expr, if the template arguments could be
/// substituted into them, or a diagnostic if substitution resulted in
/// an invalid expression.
using UnsatisfiedConstraintRecord =
std::pair<const Expr *,
llvm::PointerUnion<Expr *,
std::pair<SourceLocation, StringRef> *>>;
/// \brief The result of a constraint satisfaction check, containing the
/// necessary information to diagnose an unsatisfied constraint.
///
/// This is safe to store in an AST node, as opposed to ConstraintSatisfaction.
struct ASTConstraintSatisfaction final :
llvm::TrailingObjects<ASTConstraintSatisfaction,
UnsatisfiedConstraintRecord> {
std::size_t NumRecords;
bool IsSatisfied : 1;
const UnsatisfiedConstraintRecord *begin() const {
return getTrailingObjects<UnsatisfiedConstraintRecord>();
}
const UnsatisfiedConstraintRecord *end() const {
return getTrailingObjects<UnsatisfiedConstraintRecord>() + NumRecords;
}
ASTConstraintSatisfaction(const ASTContext &C,
const ConstraintSatisfaction &Satisfaction);
static ASTConstraintSatisfaction *
Create(const ASTContext &C, const ConstraintSatisfaction &Satisfaction);
};
/// \brief Common data class for constructs that reference concepts with
/// template arguments.
class ConceptReference {
protected:
// \brief The optional nested name specifier used when naming the concept.
NestedNameSpecifierLoc NestedNameSpec;
/// \brief The location of the template keyword, if specified when naming the
/// concept.
SourceLocation TemplateKWLoc;
/// \brief The concept name used.
DeclarationNameInfo ConceptName;
/// \brief The declaration found by name lookup when the expression was
/// created.
/// Can differ from NamedConcept when, for example, the concept was found
/// through a UsingShadowDecl.
NamedDecl *FoundDecl;
/// \brief The concept named.
ConceptDecl *NamedConcept;
/// \brief The template argument list source info used to specialize the
/// concept.
const ASTTemplateArgumentListInfo *ArgsAsWritten;
public:
ConceptReference(NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
ConceptDecl *NamedConcept,
const ASTTemplateArgumentListInfo *ArgsAsWritten) :
NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc),
ConceptName(ConceptNameInfo), FoundDecl(FoundDecl),
NamedConcept(NamedConcept), ArgsAsWritten(ArgsAsWritten) {}
ConceptReference() : NestedNameSpec(), TemplateKWLoc(), ConceptName(),
FoundDecl(nullptr), NamedConcept(nullptr), ArgsAsWritten(nullptr) {}
const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
return NestedNameSpec;
}
const DeclarationNameInfo &getConceptNameInfo() const { return ConceptName; }
SourceLocation getConceptNameLoc() const {
return getConceptNameInfo().getLoc();
}
SourceLocation getTemplateKWLoc() const { return TemplateKWLoc; }
NamedDecl *getFoundDecl() const {
return FoundDecl;
}
ConceptDecl *getNamedConcept() const {
return NamedConcept;
}
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
return ArgsAsWritten;
}
/// \brief Whether or not template arguments were explicitly specified in the
/// concept reference (they might not be in type constraints, for example)
bool hasExplicitTemplateArgs() const {
return ArgsAsWritten != nullptr;
}
};
class TypeConstraint : public ConceptReference {
/// \brief The immediately-declared constraint expression introduced by this
/// type-constraint.
Expr *ImmediatelyDeclaredConstraint = nullptr;
public:
TypeConstraint(NestedNameSpecifierLoc NNS,
DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
ConceptDecl *NamedConcept,
const ASTTemplateArgumentListInfo *ArgsAsWritten,
Expr *ImmediatelyDeclaredConstraint) :
ConceptReference(NNS, /*TemplateKWLoc=*/SourceLocation(), ConceptNameInfo,
FoundDecl, NamedConcept, ArgsAsWritten),
ImmediatelyDeclaredConstraint(ImmediatelyDeclaredConstraint) {}
/// \brief Get the immediately-declared constraint expression introduced by
/// this type-constraint, that is - the constraint expression that is added to
/// the associated constraints of the enclosing declaration in practice.
Expr *getImmediatelyDeclaredConstraint() const {
return ImmediatelyDeclaredConstraint;
}
void print(llvm::raw_ostream &OS, PrintingPolicy Policy) const;
};
} // clang
#endif // LLVM_CLANG_AST_ASTCONCEPT_H