diff options
Diffstat (limited to 'clang/include')
| -rw-r--r-- | clang/include/clang/AST/ASTConcept.h | 80 | ||||
| -rw-r--r-- | clang/include/clang/AST/ExprCXX.h | 39 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 30 | ||||
| -rw-r--r-- | clang/include/clang/Sema/Sema.h | 90 | ||||
| -rw-r--r-- | clang/include/clang/Sema/TemplateDeduction.h | 6 |
5 files changed, 227 insertions, 18 deletions
diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h new file mode 100644 index 00000000000..937a8a9b345 --- /dev/null +++ b/clang/include/clang/AST/ASTConcept.h @@ -0,0 +1,80 @@ +//===--- 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 <string> +#include <utility> +namespace clang { + +/// \brief The result of a constraint satisfaction check, containing the +/// necessary information to diagnose an unsatisfied constraint. +struct ConstraintSatisfaction { + 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; + + // This can leak if used in an AST node, use ASTConstraintSatisfaction + // instead. + void *operator new(size_t bytes, ASTContext &C) = delete; +}; + +/// 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); +}; + +} // clang + +#endif // LLVM_CLANG_AST_ASTCONCEPT_H
\ No newline at end of file diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 1eac1ce842d..1a16aa7aace 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_AST_EXPRCXX_H #define LLVM_CLANG_AST_EXPRCXX_H +#include "clang/AST/ASTConcept.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" @@ -4845,6 +4846,10 @@ class ConceptSpecializationExpr final : public Expr, TemplateArgument> { friend class ASTStmtReader; friend TrailingObjects; +public: + using SubstitutionDiagnostic = std::pair<SourceLocation, std::string>; + +protected: // \brief The optional nested name specifier used when naming the concept. NestedNameSpecifierLoc NestedNameSpec; @@ -4862,11 +4867,8 @@ class ConceptSpecializationExpr final : public Expr, /// through a UsingShadowDecl. NamedDecl *FoundDecl; - /// \brief The concept named, and whether or not the concept with the given - /// arguments was satisfied when the expression was created. - /// If any of the template arguments are dependent (this expr would then be - /// isValueDependent()), this bit is to be ignored. - llvm::PointerIntPair<ConceptDecl *, 1, bool> NamedConcept; + /// \brief The concept named. + ConceptDecl *NamedConcept; /// \brief The template argument list source info used to specialize the /// concept. @@ -4876,13 +4878,18 @@ class ConceptSpecializationExpr final : public Expr, /// converted template arguments. unsigned NumTemplateArgs; + /// \brief Information about the satisfaction of the named concept with the + /// given arguments. If this expression is value dependent, this is to be + /// ignored. + ASTConstraintSatisfaction *Satisfaction; + ConceptSpecializationExpr(ASTContext &C, NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, SourceLocation ConceptNameLoc, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, ArrayRef<TemplateArgument> ConvertedArgs, - Optional<bool> IsSatisfied); + const ConstraintSatisfaction *Satisfaction); ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs); @@ -4893,7 +4900,8 @@ public: SourceLocation TemplateKWLoc, SourceLocation ConceptNameLoc, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, - ArrayRef<TemplateArgument> ConvertedArgs, Optional<bool> IsSatisfied); + ArrayRef<TemplateArgument> ConvertedArgs, + const ConstraintSatisfaction *Satisfaction); static ConceptSpecializationExpr * Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs); @@ -4907,7 +4915,7 @@ public: } ConceptDecl *getNamedConcept() const { - return NamedConcept.getPointer(); + return NamedConcept; } ArrayRef<TemplateArgument> getTemplateArguments() const { @@ -4924,12 +4932,21 @@ public: ArrayRef<TemplateArgument> Converted); /// \brief Whether or not the concept with the given arguments was satisfied - /// when the expression was created. This method assumes that the expression - /// is not dependent! + /// when the expression was created. + /// The expression must not be dependent. bool isSatisfied() const { assert(!isValueDependent() && "isSatisfied called on a dependent ConceptSpecializationExpr"); - return NamedConcept.getInt(); + return Satisfaction->IsSatisfied; + } + + /// \brief Get elaborated satisfaction info about the template arguments' + /// satisfaction of the named concept. + /// The expression must not be dependent. + const ASTConstraintSatisfaction &getSatisfaction() const { + assert(!isValueDependent() + && "getSatisfaction called on dependent ConceptSpecializationExpr"); + return *Satisfaction; } SourceLocation getConceptNameLoc() const { return ConceptNameLoc; } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index dee585bda79..5c01dea9b77 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2572,6 +2572,26 @@ def err_non_constant_constraint_expression : Error< "expression">; def err_non_bool_atomic_constraint : Error< "atomic constraint must be of type 'bool' (found %0)">; +def err_template_arg_list_constraints_not_satisfied : Error< + "constraints not satisfied for %select{class template|function template|variable template|alias template|" + "template template parameter|template}0 %1%2">; +def note_constraints_not_satisfied : Note< + "constraints not satisfied">; +def note_substituted_constraint_expr_is_ill_formed : Note< + "because substituted constraint expression is ill-formed%0">; +def note_atomic_constraint_evaluated_to_false : Note< + "%select{and |because }0'%1' evaluated to false">; +def note_concept_specialization_constraint_evaluated_to_false : Note< + "%select{and |because }0'%1' evaluated to false">; +def note_single_arg_concept_specialization_constraint_evaluated_to_false : Note< + "%select{and |because }0%1 does not satisfy %2">; +def note_atomic_constraint_evaluated_to_false_elaborated : Note< + "%select{and |because }0'%1' (%2 %3 %4) evaluated to false">; +def err_could_not_normalize_ill_formed_constraint : Error< + "required expansion of concept specialization %0 failed, substituted " + "expression would be illegal">; +def note_could_not_normalize_ill_formed_constraint_reason : Note< + "because: %0">; def err_template_different_requires_clause : Error< "requires clause differs in template redeclaration">; @@ -3861,6 +3881,8 @@ def note_ovl_candidate_inconsistent_deduction_types : Note< def note_ovl_candidate_explicit_arg_mismatch_named : Note< "candidate template ignored: invalid explicitly-specified argument " "for template parameter %0">; +def note_ovl_candidate_unsatisfied_constraints : Note< + "candidate template ignored: constraints not satisfied%0">; def note_ovl_candidate_explicit_arg_mismatch_unnamed : Note< "candidate template ignored: invalid explicitly-specified argument " "for %ordinal0 template parameter">; @@ -4553,6 +4575,14 @@ def note_template_default_arg_checking : Note< "while checking a default template argument used here">; def note_concept_specialization_here : Note< "while checking the satisfaction of concept '%0' requested here">; +def note_checking_constraints_for_template_id_here : Note< + "while checking constraint satisfaction for template '%0' required here">; +def note_checking_constraints_for_var_spec_id_here : Note< + "while checking constraint satisfaction for variable template " + "partial specialization '%0' required here">; +def note_checking_constraints_for_class_spec_id_here : Note< + "while checking constraint satisfaction for class template partial " + "specialization '%0' required here">; def note_constraint_substitution_here : Note< "while substituting template arguments into constraint expression here">; def note_instantiation_contexts_suppressed : Note< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index e678ac5f82e..f117cca0a56 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_SEMA_SEMA_H #define LLVM_CLANG_SEMA_SEMA_H +#include "clang/AST/ASTConcept.h" #include "clang/AST/Attr.h" #include "clang/AST/Availability.h" #include "clang/AST/ComparisonCategories.h" @@ -6140,10 +6141,45 @@ public: /// A diagnostic is emitted if it is not, and false is returned. bool CheckConstraintExpression(Expr *CE); - bool CalculateConstraintSatisfaction(ConceptDecl *NamedConcept, - MultiLevelTemplateArgumentList &MLTAL, - Expr *ConstraintExpr, - bool &IsSatisfied); + /// \brief Check whether the given list of constraint expressions are + /// satisfied (as if in a 'conjunction') given template arguments. + /// \param ConstraintExprs a list of constraint expressions, treated as if + /// they were 'AND'ed together. + /// \param TemplateArgs the list of template arguments to substitute into the + /// constraint expression. + /// \param TemplateIDRange The source range of the template id that + /// caused the constraints check. + /// \param Satisfaction if true is returned, will contain details of the + /// satisfaction, with enough information to diagnose an unsatisfied + /// expression. + /// \returns true if an error occurred and satisfaction could not be checked, + /// false otherwise. + bool CheckConstraintSatisfaction(TemplateDecl *Template, + ArrayRef<const Expr *> ConstraintExprs, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange TemplateIDRange, + ConstraintSatisfaction &Satisfaction); + + bool CheckConstraintSatisfaction(ClassTemplatePartialSpecializationDecl *TD, + ArrayRef<const Expr *> ConstraintExprs, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange TemplateIDRange, + ConstraintSatisfaction &Satisfaction); + + bool CheckConstraintSatisfaction(VarTemplatePartialSpecializationDecl *TD, + ArrayRef<const Expr *> ConstraintExprs, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange TemplateIDRange, + ConstraintSatisfaction &Satisfaction); + + /// \brief Check whether the given non-dependent constraint expression is + /// satisfied. Returns false and updates Satisfaction with the satisfaction + /// verdict if successful, emits a diagnostic and returns true if an error + /// occured and satisfaction could not be determined. + /// + /// \returns true if an error occurred, false otherwise. + bool CheckConstraintSatisfaction(const Expr *ConstraintExpr, + ConstraintSatisfaction &Satisfaction); /// Check that the associated constraints of a template declaration match the /// associated constraints of an older declaration of which it is a @@ -6151,6 +6187,38 @@ public: bool CheckRedeclarationConstraintMatch(TemplateParameterList *Old, TemplateParameterList *New); + /// \brief Ensure that the given template arguments satisfy the constraints + /// associated with the given template, emitting a diagnostic if they do not. + /// + /// \param Template The template to which the template arguments are being + /// provided. + /// + /// \param TemplateArgs The converted, canonicalized template arguments. + /// + /// \param TemplateIDRange The source range of the template id that + /// caused the constraints check. + /// + /// \returns true if the constrains are not satisfied or could not be checked + /// for satisfaction, false if the constraints are satisfied. + bool EnsureTemplateArgumentListConstraints(TemplateDecl *Template, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange TemplateIDRange); + + /// \brief Emit diagnostics explaining why a constraint expression was deemed + /// unsatisfied. + void + DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction& Satisfaction); + + /// \brief Emit diagnostics explaining why a constraint expression was deemed + /// unsatisfied. + void + DiagnoseUnsatisfiedConstraint(const ASTConstraintSatisfaction& Satisfaction); + + /// \brief Emit diagnostics explaining why a constraint expression was deemed + /// unsatisfied because it was ill-formed. + void DiagnoseUnsatisfiedIllFormedConstraint(SourceLocation DiagnosticLocation, + StringRef Diagnostic); + // ParseObjCStringLiteral - Parse Objective-C string literals. ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, ArrayRef<Expr *> Strings); @@ -6966,13 +7034,18 @@ public: /// contain the converted forms of the template arguments as written. /// Otherwise, \p TemplateArgs will not be modified. /// + /// \param ConstraintsNotSatisfied If provided, and an error occured, will + /// receive true if the cause for the error is the associated constraints of + /// the template not being satisfied by the template arguments. + /// /// \returns true if an error occurred, false otherwise. bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, SmallVectorImpl<TemplateArgument> &Converted, - bool UpdateArgsWithConversions = true); + bool UpdateArgsWithConversions = true, + bool *ConstraintsNotSatisfied = nullptr); bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg, @@ -7514,6 +7587,9 @@ public: TDK_InvalidExplicitArguments, /// Checking non-dependent argument conversions failed. TDK_NonDependentConversionFailure, + /// The deduced arguments did not satisfy the constraints associated + /// with the template. + TDK_ConstraintsNotSatisfied, /// Deduction failed; that's all we know. TDK_MiscellaneousDeductionFailure, /// CUDA Target attributes do not match. @@ -8026,7 +8102,7 @@ public: /// constrained entity (a concept declaration or a template with associated /// constraints). InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - ConstraintsCheck, TemplateDecl *Template, + ConstraintsCheck, NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange); @@ -8035,7 +8111,7 @@ public: /// with a template declaration or as part of the satisfaction check of a /// concept. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - ConstraintSubstitution, TemplateDecl *Template, + ConstraintSubstitution, NamedDecl *Template, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange); diff --git a/clang/include/clang/Sema/TemplateDeduction.h b/clang/include/clang/Sema/TemplateDeduction.h index 662c4072c97..b60939c9787 100644 --- a/clang/include/clang/Sema/TemplateDeduction.h +++ b/clang/include/clang/Sema/TemplateDeduction.h @@ -14,6 +14,8 @@ #ifndef LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H #define LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H +#include "clang/Sema/Ownership.h" +#include "clang/AST/ASTConcept.h" #include "clang/AST/DeclAccessPair.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/TemplateBase.h" @@ -218,6 +220,10 @@ public: /// /// FIXME: This should be kept internal to SemaTemplateDeduction. SmallVector<DeducedPack *, 8> PendingDeducedPacks; + + /// \brief The constraint satisfaction details resulting from the associated + /// constraints satisfaction tests. + ConstraintSatisfaction AssociatedConstraintsSatisfaction; }; } // namespace sema |

