Author: Vlad Tsyrklevich Date: 2019-10-28T15:00:40-07:00 New Revision: 38839d08b8e165dfaab0fa6acc77e620d6df294c
URL: https://github.com/llvm/llvm-project/commit/38839d08b8e165dfaab0fa6acc77e620d6df294c DIFF: https://github.com/llvm/llvm-project/commit/38839d08b8e165dfaab0fa6acc77e620d6df294c.diff LOG: Revert "[Concepts] Constraint Enforcement & Diagnostics" This reverts commit ffa214ef22892d75340dc6720271863901dc2c90, it was causing ASAN test failures on sanitizer-x86_64-linux-bootstrap. Added: Modified: clang/include/clang/AST/ExprCXX.h clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Sema/Sema.h clang/include/clang/Sema/TemplateDeduction.h clang/lib/AST/ASTContext.cpp clang/lib/AST/CMakeLists.txt clang/lib/AST/Decl.cpp clang/lib/AST/ExprCXX.cpp clang/lib/Sema/SemaConcept.cpp clang/lib/Sema/SemaDeclCXX.cpp clang/lib/Sema/SemaOverload.cpp clang/lib/Sema/SemaTemplate.cpp clang/lib/Sema/SemaTemplateDeduction.cpp clang/lib/Sema/SemaTemplateInstantiate.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/lib/Serialization/ASTReaderStmt.cpp clang/lib/Serialization/ASTWriterStmt.cpp clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp Removed: clang/include/clang/AST/ASTConcept.h clang/lib/AST/ASTConcept.cpp clang/test/CXX/temp/temp.constr/temp.constr.constr/function-templates.cpp clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp ################################################################################ diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h deleted file mode 100644 index f5e99a8bfa1e..000000000000 --- a/clang/include/clang/AST/ASTConcept.h +++ /dev/null @@ -1,80 +0,0 @@ -//===--- 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, std::string>; - 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 3719f8229a36..2152e108c7cb 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -14,7 +14,6 @@ #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" @@ -4852,10 +4851,6 @@ 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; @@ -4873,8 +4868,11 @@ class ConceptSpecializationExpr final : public Expr, /// through a UsingShadowDecl. NamedDecl *FoundDecl; - /// \brief The concept named. - ConceptDecl *NamedConcept; + /// \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 template argument list source info used to specialize the /// concept. @@ -4884,18 +4882,13 @@ 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, - const ConstraintSatisfaction *Satisfaction); + Optional<bool> IsSatisfied); ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs); @@ -4906,8 +4899,7 @@ class ConceptSpecializationExpr final : public Expr, SourceLocation TemplateKWLoc, SourceLocation ConceptNameLoc, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, - ArrayRef<TemplateArgument> ConvertedArgs, - const ConstraintSatisfaction *Satisfaction); + ArrayRef<TemplateArgument> ConvertedArgs, Optional<bool> IsSatisfied); static ConceptSpecializationExpr * Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs); @@ -4921,7 +4913,7 @@ class ConceptSpecializationExpr final : public Expr, } ConceptDecl *getNamedConcept() const { - return NamedConcept; + return NamedConcept.getPointer(); } ArrayRef<TemplateArgument> getTemplateArguments() const { @@ -4938,21 +4930,12 @@ class ConceptSpecializationExpr final : public Expr, ArrayRef<TemplateArgument> Converted); /// \brief Whether or not the concept with the given arguments was satisfied - /// when the expression was created. - /// The expression must not be dependent. + /// when the expression was created. This method assumes that the expression + /// is not dependent! bool isSatisfied() const { assert(!isValueDependent() && "isSatisfied called on a dependent ConceptSpecializationExpr"); - 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; + return NamedConcept.getInt(); } SourceLocation getConceptNameLoc() const { return ConceptNameLoc; } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 20670a98fe03..2313c60f006f 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2542,26 +2542,6 @@ 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_ diff erent_requires_clause : Error< "requires clause diff ers in template redeclaration">; @@ -3849,8 +3829,6 @@ 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">; @@ -4543,14 +4521,6 @@ 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 694b923160aa..88d21367006f 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -14,7 +14,6 @@ #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" @@ -6132,45 +6131,10 @@ class Sema { /// A diagnostic is emitted if it is not, and false is returned. bool CheckConstraintExpression(Expr *CE); - /// \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); + bool CalculateConstraintSatisfaction(ConceptDecl *NamedConcept, + MultiLevelTemplateArgumentList &MLTAL, + Expr *ConstraintExpr, + bool &IsSatisfied); /// Check that the associated constraints of a template declaration match the /// associated constraints of an older declaration of which it is a @@ -6178,38 +6142,6 @@ class Sema { 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); @@ -7025,18 +6957,13 @@ class Sema { /// 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 *ConstraintsNotSatisfied = nullptr); + bool UpdateArgsWithConversions = true); bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg, @@ -7578,9 +7505,6 @@ class Sema { 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. @@ -8093,7 +8017,7 @@ class Sema { /// constrained entity (a concept declaration or a template with associated /// constraints). InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - ConstraintsCheck, NamedDecl *Template, + ConstraintsCheck, TemplateDecl *Template, ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange); @@ -8102,7 +8026,7 @@ class Sema { /// with a template declaration or as part of the satisfaction check of a /// concept. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - ConstraintSubstitution, NamedDecl *Template, + ConstraintSubstitution, TemplateDecl *Template, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange); diff --git a/clang/include/clang/Sema/TemplateDeduction.h b/clang/include/clang/Sema/TemplateDeduction.h index b60939c97872..662c4072c978 100644 --- a/clang/include/clang/Sema/TemplateDeduction.h +++ b/clang/include/clang/Sema/TemplateDeduction.h @@ -14,8 +14,6 @@ #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" @@ -220,10 +218,6 @@ class TemplateDeductionInfo { /// /// 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 diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp deleted file mode 100644 index 3446a6a6da14..000000000000 --- a/clang/lib/AST/ASTConcept.cpp +++ /dev/null @@ -1,56 +0,0 @@ -//===--- ASTConcept.cpp - 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 defines AST data structures related to concepts. -/// -//===----------------------------------------------------------------------===// - -#include "clang/AST/ASTConcept.h" -#include "clang/AST/ASTContext.h" -using namespace clang; - -ASTConstraintSatisfaction::ASTConstraintSatisfaction(const ASTContext &C, - const ConstraintSatisfaction &Satisfaction): - NumRecords{Satisfaction.Details.size()}, - IsSatisfied{Satisfaction.IsSatisfied} { - for (unsigned I = 0; I < NumRecords; ++I) { - auto &Detail = Satisfaction.Details[I]; - if (Detail.second.is<Expr *>()) - new (getTrailingObjects<UnsatisfiedConstraintRecord>() + I) - UnsatisfiedConstraintRecord{Detail.first, - UnsatisfiedConstraintRecord::second_type( - Detail.second.get<Expr *>())}; - else { - auto &SubstitutionDiagnostic = - *Detail.second.get<std::pair<SourceLocation, std::string> *>(); - unsigned MessageSize = SubstitutionDiagnostic.second.size(); - char *Mem = new (C) char[MessageSize + 1]; - memcpy(Mem, SubstitutionDiagnostic.second.c_str(), MessageSize); - Mem[MessageSize + 1] = '\0'; - auto *NewSubstDiag = new (C) std::pair<SourceLocation, StringRef>( - SubstitutionDiagnostic.first, StringRef(Mem)); - new (getTrailingObjects<UnsatisfiedConstraintRecord>() + I) - UnsatisfiedConstraintRecord{Detail.first, - UnsatisfiedConstraintRecord::second_type( - NewSubstDiag)}; - } - } -} - - -ASTConstraintSatisfaction * -ASTConstraintSatisfaction::Create(const ASTContext &C, - const ConstraintSatisfaction &Satisfaction) { - std::size_t size = - totalSizeToAlloc<UnsatisfiedConstraintRecord>( - Satisfaction.Details.size()); - void *Mem = C.Allocate(size, alignof(ASTConstraintSatisfaction)); - return new (Mem) ASTConstraintSatisfaction(C, Satisfaction); -} diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index cdd05c02ef36..cda51ec755a8 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -14,7 +14,6 @@ #include "CXXABI.h" #include "Interp/Context.h" #include "clang/AST/APValue.h" -#include "clang/AST/ASTConcept.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Attr.h" diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt index 1ede58cc9ed6..5bae40c86539 100644 --- a/clang/lib/AST/CMakeLists.txt +++ b/clang/lib/AST/CMakeLists.txt @@ -14,7 +14,6 @@ clang_tablegen(Opcodes.inc add_clang_library(clangAST APValue.cpp - ASTConcept.cpp ASTConsumer.cpp ASTContext.cpp ASTDiagnostic.cpp diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 03fb55db14ef..66446626c2eb 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -4585,7 +4585,7 @@ LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, unsigned ID) { } void LabelDecl::setMSAsmLabel(StringRef Name) { -char *Buffer = new (getASTContext(), 1) char[Name.size() + 1]; + char *Buffer = new (getASTContext(), 1) char[Name.size() + 1]; memcpy(Buffer, Name.data(), Name.size()); Buffer[Name.size()] = '\0'; MSAsmName = Buffer; diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index a6252d45b267..904928bdf286 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -1755,19 +1755,18 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(ASTContext &C, NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, SourceLocation ConceptNameLoc, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, - ArrayRef<TemplateArgument> ConvertedArgs, - const ConstraintSatisfaction *Satisfaction) + ArrayRef<TemplateArgument> ConvertedArgs, Optional<bool> IsSatisfied) : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary, /*TypeDependent=*/false, // All the flags below are set in setTemplateArguments. - /*ValueDependent=*/!Satisfaction, /*InstantiationDependent=*/false, + /*ValueDependent=*/!IsSatisfied.hasValue(), + /*InstantiationDependent=*/false, /*ContainsUnexpandedParameterPacks=*/false), NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc), ConceptNameLoc(ConceptNameLoc), FoundDecl(FoundDecl), - NamedConcept(NamedConcept), NumTemplateArgs(ConvertedArgs.size()), - Satisfaction(Satisfaction ? - ASTConstraintSatisfaction::Create(C, *Satisfaction) : - nullptr) { + NamedConcept(NamedConcept, IsSatisfied ? *IsSatisfied : true), + NumTemplateArgs(ConvertedArgs.size()) { + setTemplateArguments(ArgsAsWritten, ConvertedArgs); } @@ -1814,13 +1813,13 @@ ConceptSpecializationExpr::Create(ASTContext &C, NestedNameSpecifierLoc NNS, ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, ArrayRef<TemplateArgument> ConvertedArgs, - const ConstraintSatisfaction *Satisfaction) { + Optional<bool> IsSatisfied) { void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>( ConvertedArgs.size())); return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc, ConceptNameLoc, FoundDecl, NamedConcept, ArgsAsWritten, - ConvertedArgs, Satisfaction); + ConvertedArgs, IsSatisfied); } ConceptSpecializationExpr * diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index cbe265971df6..848ccf543445 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -12,13 +12,10 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/Sema.h" -#include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/Template.h" #include "clang/AST/ExprCXX.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/PointerUnion.h" using namespace clang; using namespace sema; @@ -49,367 +46,80 @@ bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) { return true; } -template <typename AtomicEvaluator> -static bool -calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, - ConstraintSatisfaction &Satisfaction, - AtomicEvaluator &&Evaluator) { +bool +Sema::CalculateConstraintSatisfaction(ConceptDecl *NamedConcept, + MultiLevelTemplateArgumentList &MLTAL, + Expr *ConstraintExpr, + bool &IsSatisfied) { ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts(); if (auto *BO = dyn_cast<BinaryOperator>(ConstraintExpr)) { - if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) { - if (calculateConstraintSatisfaction(S, BO->getLHS(), Satisfaction, - Evaluator)) + if (BO->getOpcode() == BO_LAnd) { + if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(), + IsSatisfied)) return true; - - bool IsLHSSatisfied = Satisfaction.IsSatisfied; - - if (BO->getOpcode() == BO_LOr && IsLHSSatisfied) - // [temp.constr.op] p3 - // A disjunction is a constraint taking two operands. To determine if - // a disjunction is satisfied, the satisfaction of the first operand - // is checked. If that is satisfied, the disjunction is satisfied. - // Otherwise, the disjunction is satisfied if and only if the second - // operand is satisfied. + if (!IsSatisfied) return false; - - if (BO->getOpcode() == BO_LAnd && !IsLHSSatisfied) - // [temp.constr.op] p2 - // A conjunction is a constraint taking two operands. To determine if - // a conjunction is satisfied, the satisfaction of the first operand - // is checked. If that is not satisfied, the conjunction is not - // satisfied. Otherwise, the conjunction is satisfied if and only if - // the second operand is satisfied. + return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(), + IsSatisfied); + } else if (BO->getOpcode() == BO_LOr) { + if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(), + IsSatisfied)) + return true; + if (IsSatisfied) return false; - - return calculateConstraintSatisfaction(S, BO->getRHS(), Satisfaction, - std::forward<AtomicEvaluator>(Evaluator)); + return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(), + IsSatisfied); } } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) - return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction, - std::forward<AtomicEvaluator>(Evaluator)); - - // An atomic constraint expression - ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr); - - if (SubstitutedAtomicExpr.isInvalid()) - return true; - - if (!SubstitutedAtomicExpr.isUsable()) - // Evaluator has decided satisfaction without yielding an expression. - return false; + return CalculateConstraintSatisfaction(NamedConcept, MLTAL, C->getSubExpr(), + IsSatisfied); EnterExpressionEvaluationContext ConstantEvaluated( - S, Sema::ExpressionEvaluationContext::ConstantEvaluated); - SmallVector<PartialDiagnosticAt, 2> EvaluationDiags; - Expr::EvalResult EvalResult; - EvalResult.Diag = &EvaluationDiags; - if (!SubstitutedAtomicExpr.get()->EvaluateAsRValue(EvalResult, S.Context)) { - // C++2a [temp.constr.atomic]p1 - // ...E shall be a constant expression of type bool. - S.Diag(SubstitutedAtomicExpr.get()->getBeginLoc(), - diag::err_non_constant_constraint_expression) - << SubstitutedAtomicExpr.get()->getSourceRange(); - for (const PartialDiagnosticAt &PDiag : EvaluationDiags) - S.Diag(PDiag.first, PDiag.second); - return true; - } - - Satisfaction.IsSatisfied = EvalResult.Val.getInt().getBoolValue(); - if (!Satisfaction.IsSatisfied) - Satisfaction.Details.emplace_back(ConstraintExpr, - SubstitutedAtomicExpr.get()); - - return false; -} - -template <typename TemplateDeclT> -static bool calculateConstraintSatisfaction( - Sema &S, TemplateDeclT *Template, ArrayRef<TemplateArgument> TemplateArgs, - SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL, - const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) { - return calculateConstraintSatisfaction( - S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) { - EnterExpressionEvaluationContext ConstantEvaluated( - S, Sema::ExpressionEvaluationContext::ConstantEvaluated); - - // Atomic constraint - substitute arguments and check satisfaction. - ExprResult SubstitutedExpression; - { - TemplateDeductionInfo Info(TemplateNameLoc); - Sema::InstantiatingTemplate Inst(S, AtomicExpr->getBeginLoc(), - Sema::InstantiatingTemplate::ConstraintSubstitution{}, Template, - Info, AtomicExpr->getSourceRange()); - if (Inst.isInvalid()) - return ExprError(); - // We do not want error diagnostics escaping here. - Sema::SFINAETrap Trap(S); - SubstitutedExpression = S.SubstExpr(const_cast<Expr *>(AtomicExpr), - MLTAL); - if (SubstitutedExpression.isInvalid() || Trap.hasErrorOccurred()) { - // C++2a [temp.constr.atomic]p1 - // ...If substitution results in an invalid type or expression, the - // constraint is not satisfied. - if (!Trap.hasErrorOccurred()) - // A non-SFINAE error has occured as a result of this - // substitution. - return ExprError(); - - PartialDiagnosticAt SubstDiag{SourceLocation(), - PartialDiagnostic::NullDiagnostic()}; - Info.takeSFINAEDiagnostic(SubstDiag); - // FIXME: Concepts: This is an unfortunate consequence of there - // being no serialization code for PartialDiagnostics and the fact - // that serializing them would likely take a lot more storage than - // just storing them as strings. We would still like, in the - // future, to serialize the proper PartialDiagnostic as serializing - // it as a string defeats the purpose of the diagnostic mechanism. - SmallString<128> DiagString; - DiagString = ": "; - SubstDiag.second.EmitToString(S.getDiagnostics(), DiagString); - Satisfaction.Details.emplace_back( - AtomicExpr, - new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{ - SubstDiag.first, - std::string(DiagString.begin(), DiagString.end())}); - Satisfaction.IsSatisfied = false; - return ExprEmpty(); - } - } - - if (!S.CheckConstraintExpression(SubstitutedExpression.get())) - return ExprError(); - - return SubstitutedExpression; - }); -} - -template<typename TemplateDeclT> -static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template, - ArrayRef<const Expr *> ConstraintExprs, - ArrayRef<TemplateArgument> TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction) { - if (ConstraintExprs.empty()) { - Satisfaction.IsSatisfied = true; - return false; - } + *this, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + // Atomic constraint - substitute arguments and check satisfaction. + ExprResult E; + { + TemplateDeductionInfo Info(ConstraintExpr->getBeginLoc()); + InstantiatingTemplate Inst(*this, ConstraintExpr->getBeginLoc(), + InstantiatingTemplate::ConstraintSubstitution{}, + NamedConcept, Info, + ConstraintExpr->getSourceRange()); + if (Inst.isInvalid()) + return true; + // We do not want error diagnostics escaping here. + Sema::SFINAETrap Trap(*this); - for (auto& Arg : TemplateArgs) - if (Arg.isInstantiationDependent()) { - // No need to check satisfaction for dependent constraint expressions. - Satisfaction.IsSatisfied = true; + E = SubstExpr(ConstraintExpr, MLTAL); + if (E.isInvalid() || Trap.hasErrorOccurred()) { + // C++2a [temp.constr.atomic]p1 + // ...If substitution results in an invalid type or expression, the + // constraint is not satisfied. + IsSatisfied = false; return false; } - - Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(), - Sema::InstantiatingTemplate::ConstraintsCheck{}, Template, TemplateArgs, - TemplateIDRange); - if (Inst.isInvalid()) - return true; - - MultiLevelTemplateArgumentList MLTAL; - MLTAL.addOuterTemplateArguments(TemplateArgs); - - for (const Expr *ConstraintExpr : ConstraintExprs) { - if (calculateConstraintSatisfaction(S, Template, TemplateArgs, - TemplateIDRange.getBegin(), MLTAL, - ConstraintExpr, Satisfaction)) - return true; - if (!Satisfaction.IsSatisfied) - // [temp.constr.op] p2 - // [...] To determine if a conjunction is satisfied, the satisfaction - // of the first operand is checked. If that is not satisfied, the - // conjunction is not satisfied. [...] - return false; } - return false; -} - -bool Sema::CheckConstraintSatisfaction(TemplateDecl *Template, - ArrayRef<const Expr *> ConstraintExprs, - ArrayRef<TemplateArgument> TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction) { - return ::CheckConstraintSatisfaction(*this, Template, ConstraintExprs, - TemplateArgs, TemplateIDRange, - Satisfaction); -} -bool -Sema::CheckConstraintSatisfaction(ClassTemplatePartialSpecializationDecl* Part, - ArrayRef<const Expr *> ConstraintExprs, - ArrayRef<TemplateArgument> TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction) { - return ::CheckConstraintSatisfaction(*this, Part, ConstraintExprs, - TemplateArgs, TemplateIDRange, - Satisfaction); -} - -bool -Sema::CheckConstraintSatisfaction(VarTemplatePartialSpecializationDecl* Partial, - ArrayRef<const Expr *> ConstraintExprs, - ArrayRef<TemplateArgument> TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction) { - return ::CheckConstraintSatisfaction(*this, Partial, ConstraintExprs, - TemplateArgs, TemplateIDRange, - Satisfaction); -} - -bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr, - ConstraintSatisfaction &Satisfaction) { - return calculateConstraintSatisfaction( - *this, ConstraintExpr, Satisfaction, - [](const Expr *AtomicExpr) -> ExprResult { - return ExprResult(const_cast<Expr *>(AtomicExpr)); - }); -} - -bool Sema::EnsureTemplateArgumentListConstraints( - TemplateDecl *TD, ArrayRef<TemplateArgument> TemplateArgs, - SourceRange TemplateIDRange) { - ConstraintSatisfaction Satisfaction; - llvm::SmallVector<const Expr *, 3> AssociatedConstraints; - TD->getAssociatedConstraints(AssociatedConstraints); - if (CheckConstraintSatisfaction(TD, AssociatedConstraints, TemplateArgs, - TemplateIDRange, Satisfaction)) + if (!CheckConstraintExpression(E.get())) return true; - if (!Satisfaction.IsSatisfied) { - SmallString<128> TemplateArgString; - TemplateArgString = " "; - TemplateArgString += getTemplateArgumentBindingsText( - TD->getTemplateParameters(), TemplateArgs.data(), TemplateArgs.size()); - - Diag(TemplateIDRange.getBegin(), - diag::err_template_arg_list_constraints_not_satisfied) - << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)) << TD - << TemplateArgString << TemplateIDRange; - DiagnoseUnsatisfiedConstraint(Satisfaction); + SmallVector<PartialDiagnosticAt, 2> EvaluationDiags; + Expr::EvalResult EvalResult; + EvalResult.Diag = &EvaluationDiags; + if (!E.get()->EvaluateAsRValue(EvalResult, Context)) { + // C++2a [temp.constr.atomic]p1 + // ...E shall be a constant expression of type bool. + Diag(E.get()->getBeginLoc(), + diag::err_non_constant_constraint_expression) + << E.get()->getSourceRange(); + for (const PartialDiagnosticAt &PDiag : EvaluationDiags) + Diag(PDiag.first, PDiag.second); return true; } - return false; -} - -static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S, - Expr *SubstExpr, - bool First = true) { - SubstExpr = SubstExpr->IgnoreParenImpCasts(); - if (BinaryOperator *BO = dyn_cast<BinaryOperator>(SubstExpr)) { - switch (BO->getOpcode()) { - // These two cases will in practice only be reached when using fold - // expressions with || and &&, since otherwise the || and && will have been - // broken down into atomic constraints during satisfaction checking. - case BO_LOr: - // Or evaluated to false - meaning both RHS and LHS evaluated to false. - diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getLHS(), First); - diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(), - /*First=*/false); - return; - case BO_LAnd: - bool LHSSatisfied; - BO->getLHS()->EvaluateAsBooleanCondition(LHSSatisfied, S.Context); - if (LHSSatisfied) { - // LHS is true, so RHS must be false. - diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(), First); - return; - } - // LHS is false - diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getLHS(), First); - - // RHS might also be false - bool RHSSatisfied; - BO->getRHS()->EvaluateAsBooleanCondition(RHSSatisfied, S.Context); - if (!RHSSatisfied) - diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(), - /*First=*/false); - return; - case BO_GE: - case BO_LE: - case BO_GT: - case BO_LT: - case BO_EQ: - case BO_NE: - if (BO->getLHS()->getType()->isIntegerType() && - BO->getRHS()->getType()->isIntegerType()) { - Expr::EvalResult SimplifiedLHS; - Expr::EvalResult SimplifiedRHS; - BO->getLHS()->EvaluateAsInt(SimplifiedLHS, S.Context); - BO->getRHS()->EvaluateAsInt(SimplifiedRHS, S.Context); - if (!SimplifiedLHS.Diag && ! SimplifiedRHS.Diag) { - S.Diag(SubstExpr->getBeginLoc(), - diag::note_atomic_constraint_evaluated_to_false_elaborated) - << (int)First << SubstExpr - << SimplifiedLHS.Val.getInt().toString(10) - << BinaryOperator::getOpcodeStr(BO->getOpcode()) - << SimplifiedRHS.Val.getInt().toString(10); - return; - } - } - break; - - default: - break; - } - } else if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(SubstExpr)) { - if (CSE->getTemplateArgsAsWritten()->NumTemplateArgs == 1) { - S.Diag( - CSE->getSourceRange().getBegin(), - diag:: - note_single_arg_concept_specialization_constraint_evaluated_to_false) - << (int)First - << CSE->getTemplateArgsAsWritten()->arguments()[0].getArgument() - << CSE->getNamedConcept(); - } else { - S.Diag(SubstExpr->getSourceRange().getBegin(), - diag::note_concept_specialization_constraint_evaluated_to_false) - << (int)First << CSE; - } - S.DiagnoseUnsatisfiedConstraint(CSE->getSatisfaction()); - return; - } - - S.Diag(SubstExpr->getSourceRange().getBegin(), - diag::note_atomic_constraint_evaluated_to_false) - << (int)First << SubstExpr; -} -template<typename SubstitutionDiagnostic> -static void diagnoseUnsatisfiedConstraintExpr( - Sema &S, const Expr *E, - const llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> &Record, - bool First = true) { - if (auto *Diag = Record.template dyn_cast<SubstitutionDiagnostic *>()){ - S.Diag(Diag->first, diag::note_substituted_constraint_expr_is_ill_formed) - << Diag->second; - return; - } + IsSatisfied = EvalResult.Val.getInt().getBoolValue(); - diagnoseWellFormedUnsatisfiedConstraintExpr(S, - Record.template get<Expr *>(), First); -} - -void Sema::DiagnoseUnsatisfiedConstraint( - const ConstraintSatisfaction& Satisfaction) { - assert(!Satisfaction.IsSatisfied && - "Attempted to diagnose a satisfied constraint"); - bool First = true; - for (auto &Pair : Satisfaction.Details) { - diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First); - First = false; - } -} - -void Sema::DiagnoseUnsatisfiedConstraint( - const ASTConstraintSatisfaction &Satisfaction) { - assert(!Satisfaction.IsSatisfied && - "Attempted to diagnose a satisfied constraint"); - bool First = true; - for (auto &Pair : Satisfaction) { - diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First); - First = false; - } + return false; } \ No newline at end of file diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 6a718db6c553..e3f57e347268 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -14486,16 +14486,8 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, std::string InnerCondDescription; std::tie(InnerCond, InnerCondDescription) = findFailedBooleanCondition(Converted.get()); - if (InnerCond && isa<ConceptSpecializationExpr>(InnerCond)) { - // Drill down into concept specialization expressions to see why they - // weren't satisfied. - Diag(StaticAssertLoc, diag::err_static_assert_failed) - << !AssertMessage << Msg.str() << AssertExpr->getSourceRange(); - ConstraintSatisfaction Satisfaction; - if (!CheckConstraintSatisfaction(InnerCond, Satisfaction)) - DiagnoseUnsatisfiedConstraint(Satisfaction); - } else if (InnerCond && !isa<CXXBoolLiteralExpr>(InnerCond) - && !isa<IntegerLiteral>(InnerCond)) { + if (InnerCond && !isa<CXXBoolLiteralExpr>(InnerCond) + && !isa<IntegerLiteral>(InnerCond)) { Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed) << InnerCondDescription << !AssertMessage << Msg.str() << InnerCond->getSourceRange(); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 4417d22d133e..1547108b4af6 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -591,12 +591,6 @@ namespace { TemplateArgumentList *TemplateArgs; unsigned CallArgIndex; }; - // Structure used by DeductionFailureInfo to store information about - // unsatisfied constraints. - struct CNSInfo { - TemplateArgumentList *TemplateArgs; - ConstraintSatisfaction Satisfaction; - }; } /// Convert from Sema's representation of template deduction information @@ -667,14 +661,6 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, } break; - case Sema::TDK_ConstraintsNotSatisfied: { - CNSInfo *Saved = new (Context) CNSInfo; - Saved->TemplateArgs = Info.take(); - Saved->Satisfaction = Info.AssociatedConstraintsSatisfaction; - Result.Data = Saved; - break; - } - case Sema::TDK_Success: case Sema::TDK_NonDependentConversionFailure: llvm_unreachable("not a deduction failure"); @@ -715,15 +701,6 @@ void DeductionFailureInfo::Destroy() { } break; - case Sema::TDK_ConstraintsNotSatisfied: - // FIXME: Destroy the template argument list? - Data = nullptr; - if (PartialDiagnosticAt *Diag = getSFINAEDiagnostic()) { - Diag->~PartialDiagnosticAt(); - HasDiagnostic = false; - } - break; - // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: break; @@ -749,7 +726,6 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() { case Sema::TDK_NonDeducedMismatch: case Sema::TDK_CUDATargetMismatch: case Sema::TDK_NonDependentConversionFailure: - case Sema::TDK_ConstraintsNotSatisfied: return TemplateParameter(); case Sema::TDK_Incomplete: @@ -793,9 +769,6 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() { case Sema::TDK_SubstitutionFailure: return static_cast<TemplateArgumentList*>(Data); - case Sema::TDK_ConstraintsNotSatisfied: - return static_cast<CNSInfo*>(Data)->TemplateArgs; - // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: break; @@ -816,7 +789,6 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() { case Sema::TDK_SubstitutionFailure: case Sema::TDK_CUDATargetMismatch: case Sema::TDK_NonDependentConversionFailure: - case Sema::TDK_ConstraintsNotSatisfied: return nullptr; case Sema::TDK_IncompletePack: @@ -848,7 +820,6 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() { case Sema::TDK_SubstitutionFailure: case Sema::TDK_CUDATargetMismatch: case Sema::TDK_NonDependentConversionFailure: - case Sema::TDK_ConstraintsNotSatisfied: return nullptr; case Sema::TDK_Inconsistent: @@ -1284,8 +1255,6 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, return NewTarget != OldTarget; } - // TODO: Concepts: Check function trailing requires clauses here. - // The signatures match; this is not an overload. return false; } @@ -10380,21 +10349,6 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, MaybeEmitInheritedConstructorNote(S, Found); return; - case Sema::TDK_ConstraintsNotSatisfied: { - // Format the template argument list into the argument string. - SmallString<128> TemplateArgString; - TemplateArgumentList *Args = DeductionFailure.getTemplateArgumentList(); - TemplateArgString = " "; - TemplateArgString += S.getTemplateArgumentBindingsText( - getDescribedTemplate(Templated)->getTemplateParameters(), *Args); - S.Diag(Templated->getLocation(), - diag::note_ovl_candidate_unsatisfied_constraints) - << TemplateArgString; - - S.DiagnoseUnsatisfiedConstraint( - static_cast<CNSInfo*>(DeductionFailure.Data)->Satisfaction); - return; - } case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: DiagnoseArityMismatch(S, Found, Templated, NumArgs); @@ -10847,7 +10801,6 @@ static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) { case Sema::TDK_SubstitutionFailure: case Sema::TDK_DeducedMismatch: - case Sema::TDK_ConstraintsNotSatisfied: case Sema::TDK_DeducedMismatchNested: case Sema::TDK_NonDeducedMismatch: case Sema::TDK_MiscellaneousDeductionFailure: diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 3003a9a889df..3f2d38630c36 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3210,7 +3210,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, TemplateDecl *Template = Name.getAsTemplateDecl(); if (!Template || isa<FunctionTemplateDecl>(Template) || - isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(Template)) { + isa<VarTemplateDecl>(Template) || + isa<ConceptDecl>(Template)) { // We might have a substituted template template parameter pack. If so, // build a template specialization type for it. if (Name.getAsSubstTemplateTemplateParmPack()) @@ -3226,8 +3227,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // template. SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, - false, Converted, - /*UpdateArgsWithConversion=*/true)) + false, Converted)) return QualType(); QualType CanonType; @@ -3235,7 +3235,6 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, bool InstantiationDependent = false; if (TypeAliasTemplateDecl *AliasTemplate = dyn_cast<TypeAliasTemplateDecl>(Template)) { - // Find the canonical type for this type alias template specialization. TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl(); if (Pattern->isInvalidDecl()) @@ -3873,8 +3872,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // template. SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs, - false, Converted, - /*UpdateArgsWithConversion=*/true)) + false, Converted)) return true; // Find the variable template (partial) specialization declaration that @@ -4045,7 +4043,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, if (CheckTemplateArgumentList( Template, TemplateNameLoc, const_cast<TemplateArgumentListInfo &>(TemplateArgs), false, - Converted, /*UpdateArgsWithConversion=*/true)) + Converted)) return true; // Find the variable template specialization declaration that @@ -4236,7 +4234,7 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, /*UpdateArgsWithConversion=*/false)) return ExprError(); - ConstraintSatisfaction Satisfaction; + Optional<bool> IsSatisfied; bool AreArgsDependent = false; for (TemplateArgument &Arg : Converted) { if (Arg.isDependent()) { @@ -4244,21 +4242,25 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, break; } } - if (!AreArgsDependent && - CheckConstraintSatisfaction(NamedConcept, - {NamedConcept->getConstraintExpr()}, - Converted, - SourceRange(SS.isSet() ? SS.getBeginLoc() : - ConceptNameLoc, - TemplateArgs->getRAngleLoc()), - Satisfaction)) + if (!AreArgsDependent) { + InstantiatingTemplate Inst(*this, ConceptNameLoc, + InstantiatingTemplate::ConstraintsCheck{}, NamedConcept, Converted, + SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameLoc, + TemplateArgs->getRAngleLoc())); + MultiLevelTemplateArgumentList MLTAL; + MLTAL.addOuterTemplateArguments(Converted); + bool Satisfied; + if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, + NamedConcept->getConstraintExpr(), + Satisfied)) return ExprError(); - + IsSatisfied = Satisfied; + } return ConceptSpecializationExpr::Create(Context, SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{}, TemplateKWLoc, ConceptNameLoc, FoundDecl, NamedConcept, ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted, - AreArgsDependent ? nullptr : &Satisfaction); + IsSatisfied); } ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, @@ -5204,11 +5206,7 @@ bool Sema::CheckTemplateArgumentList( TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, SmallVectorImpl<TemplateArgument> &Converted, - bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied) { - - if (ConstraintsNotSatisfied) - *ConstraintsNotSatisfied = false; - + bool UpdateArgsWithConversions) { // Make a copy of the template arguments for processing. Only make the // changes at the end when successful in matching the arguments to the // template. @@ -5323,6 +5321,7 @@ bool Sema::CheckTemplateArgumentList( if ((*Param)->isTemplateParameterPack() && !ArgumentPack.empty()) Converted.push_back( TemplateArgument::CreatePackCopy(Context, ArgumentPack)); + return false; } @@ -5461,15 +5460,6 @@ bool Sema::CheckTemplateArgumentList( if (UpdateArgsWithConversions) TemplateArgs = std::move(NewArgs); - if (!PartialTemplateArgs && - EnsureTemplateArgumentListConstraints( - Template, Converted, SourceRange(TemplateLoc, - TemplateArgs.getRAngleLoc()))) { - if (ConstraintsNotSatisfied) - *ConstraintsNotSatisfied = true; - return true; - } - return false; } @@ -7804,8 +7794,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization( // template. SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, - TemplateArgs, false, Converted, - /*UpdateArgsWithConversion=*/true)) + TemplateArgs, false, Converted)) return true; // Find the class template (partial) specialization declaration that @@ -9051,8 +9040,7 @@ DeclResult Sema::ActOnExplicitInstantiation( // template. SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, - TemplateArgs, false, Converted, - /*UpdateArgsWithConversion=*/true)) + TemplateArgs, false, Converted)) return true; // Find the class template specialization declaration that diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 327447746c39..64ef819e30d4 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -2591,23 +2591,6 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, return ConvertArg(Arg, 0); } -template<typename TemplateDeclT> -static Sema::TemplateDeductionResult -CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template, - ArrayRef<TemplateArgument> DeducedArgs, - TemplateDeductionInfo &Info) { - llvm::SmallVector<const Expr *, 3> AssociatedConstraints; - Template->getAssociatedConstraints(AssociatedConstraints); - if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, - DeducedArgs, Info.getLocation(), - Info.AssociatedConstraintsSatisfaction) || - !Info.AssociatedConstraintsSatisfaction.IsSatisfied) { - Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs)); - return Sema::TDK_ConstraintsNotSatisfied; - } - return Sema::TDK_Success; -} - // FIXME: This should not be a template, but // ClassTemplatePartialSpecializationDecl sadly does not derive from // TemplateDecl. @@ -2705,10 +2688,6 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( // If we get here, we successfully used the default template argument. } - if (Sema::TemplateDeductionResult Result - = CheckDeducedArgumentConstraints(S, Template, Builder, Info)) - return Result; - return Sema::TDK_Success; } @@ -2788,14 +2767,10 @@ FinishTemplateArgumentDeduction( return Sema::TDK_SubstitutionFailure; } - bool ConstraintsNotSatisfied; SmallVector<TemplateArgument, 4> ConvertedInstArgs; if (S.CheckTemplateArgumentList(Template, Partial->getLocation(), InstArgs, - false, ConvertedInstArgs, - /*UpdateArgsWithConversions=*/true, - &ConstraintsNotSatisfied)) - return ConstraintsNotSatisfied ? Sema::TDK_ConstraintsNotSatisfied : - Sema::TDK_SubstitutionFailure; + false, ConvertedInstArgs)) + return Sema::TDK_SubstitutionFailure; TemplateParameterList *TemplateParams = Template->getTemplateParameters(); for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { @@ -2856,6 +2831,7 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction( return Sema::TDK_Success; } + /// Perform template argument deduction to determine whether /// the given template arguments match the given class template /// partial specialization per C++ [temp.class.spec.match]. @@ -5073,7 +5049,6 @@ template<typename TemplateLikeDecl> static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, TemplateLikeDecl *P2, TemplateDeductionInfo &Info) { - // TODO: Concepts: Regard constraints // C++ [temp.class.order]p1: // For two class template partial specializations, the first is at least as // specialized as the second if, given the following rewrite to two diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index e6c3ab422067..0daa33cfbef5 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -363,7 +363,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, - ConstraintsCheck, NamedDecl *Template, + ConstraintsCheck, TemplateDecl *Template, ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange) : InstantiatingTemplate( SemaRef, CodeSynthesisContext::ConstraintsCheck, @@ -372,7 +372,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, - ConstraintSubstitution, NamedDecl *Template, + ConstraintSubstitution, TemplateDecl *Template, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) : InstantiatingTemplate( SemaRef, CodeSynthesisContext::ConstraintSubstitution, @@ -691,27 +691,24 @@ void Sema::PrintInstantiationStack() { case CodeSynthesisContext::Memoization: break; - case CodeSynthesisContext::ConstraintsCheck: { - unsigned DiagID = 0; - if (isa<ConceptDecl>(Active->Entity)) - DiagID = diag::note_concept_specialization_here; - else if (isa<TemplateDecl>(Active->Entity)) - DiagID = diag::note_checking_constraints_for_template_id_here; - else if (isa<VarTemplatePartialSpecializationDecl>(Active->Entity)) - DiagID = diag::note_checking_constraints_for_var_spec_id_here; - else { - assert(isa<ClassTemplatePartialSpecializationDecl>(Active->Entity)); - DiagID = diag::note_checking_constraints_for_class_spec_id_here; + case CodeSynthesisContext::ConstraintsCheck: + if (auto *CD = dyn_cast<ConceptDecl>(Active->Entity)) { + SmallVector<char, 128> TemplateArgsStr; + llvm::raw_svector_ostream OS(TemplateArgsStr); + CD->printName(OS); + printTemplateArgumentList(OS, Active->template_arguments(), + getPrintingPolicy()); + Diags.Report(Active->PointOfInstantiation, + diag::note_concept_specialization_here) + << OS.str() + << Active->InstantiationRange; + break; } - SmallVector<char, 128> TemplateArgsStr; - llvm::raw_svector_ostream OS(TemplateArgsStr); - cast<NamedDecl>(Active->Entity)->printName(OS); - printTemplateArgumentList(OS, Active->template_arguments(), - getPrintingPolicy()); - Diags.Report(Active->PointOfInstantiation, DiagID) << OS.str() - << Active->InstantiationRange; + // TODO: Concepts - implement this for constrained templates and partial + // specializations. + llvm_unreachable("only concept constraints are supported right now"); break; - } + case CodeSynthesisContext::ConstraintSubstitution: Diags.Report(Active->PointOfInstantiation, diag::note_constraint_substitution_here) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index c1d7b7f84f30..31a4302ba826 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3279,8 +3279,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( D->getLocation(), InstTemplateArgs, false, - Converted, - /*UpdateArgsWithConversion=*/true)) + Converted)) return nullptr; // Figure out where to insert this class template explicit specialization @@ -3401,8 +3400,7 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( // Check that the template argument list is well-formed for this template. SmallVector<TemplateArgument, 4> Converted; if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(), - VarTemplateArgsInfo, false, Converted, - /*UpdateArgsWithConversion=*/true)) + VarTemplateArgsInfo, false, Converted)) return nullptr; // Check whether we've already seen a declaration of this specialization. diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index f5d659affac7..a275e0c30579 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "clang/Serialization/ASTReader.h" -#include "clang/AST/ASTConcept.h" #include "clang/AST/ASTContext.h" #include "clang/AST/AttrIterator.h" #include "clang/AST/Decl.h" @@ -743,33 +742,14 @@ void ASTStmtReader::VisitConceptSpecializationExpr( E->TemplateKWLoc = Record.readSourceLocation(); E->ConceptNameLoc = Record.readSourceLocation(); E->FoundDecl = ReadDeclAs<NamedDecl>(); - E->NamedConcept = ReadDeclAs<ConceptDecl>(); + E->NamedConcept.setPointer(ReadDeclAs<ConceptDecl>()); const ASTTemplateArgumentListInfo *ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); llvm::SmallVector<TemplateArgument, 4> Args; for (unsigned I = 0; I < NumTemplateArgs; ++I) Args.push_back(Record.readTemplateArgument()); E->setTemplateArguments(ArgsAsWritten, Args); - ConstraintSatisfaction Satisfaction; - Satisfaction.IsSatisfied = Record.readInt(); - if (!Satisfaction.IsSatisfied) { - unsigned NumDetailRecords = Record.readInt(); - for (unsigned i = 0; i != NumDetailRecords; ++i) { - Expr *ConstraintExpr = Record.readExpr(); - bool IsDiagnostic = Record.readInt(); - if (IsDiagnostic) { - SourceLocation DiagLocation = Record.readSourceLocation(); - std::string DiagMessage = Record.readString(); - Satisfaction.Details.emplace_back( - ConstraintExpr, new (Record.getContext()) - ConstraintSatisfaction::SubstitutionDiagnostic{ - DiagLocation, DiagMessage}); - } else - Satisfaction.Details.emplace_back(ConstraintExpr, Record.readExpr()); - } - } - E->Satisfaction = ASTConstraintSatisfaction::Create(Record.getContext(), - Satisfaction); + E->NamedConcept.setInt(Record.readInt() == 1); } void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 671e55e14521..c39d4d39bcdf 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -401,25 +401,7 @@ void ASTStmtWriter::VisitConceptSpecializationExpr( Record.AddASTTemplateArgumentListInfo(E->getTemplateArgsAsWritten()); for (const TemplateArgument &Arg : TemplateArgs) Record.AddTemplateArgument(Arg); - const ASTConstraintSatisfaction &Satisfaction = E->getSatisfaction(); - Record.push_back(Satisfaction.IsSatisfied); - if (!Satisfaction.IsSatisfied) { - Record.push_back(Satisfaction.NumRecords); - for (const auto &DetailRecord : Satisfaction) { - Record.AddStmt(const_cast<Expr *>(DetailRecord.first)); - auto *E = DetailRecord.second.dyn_cast<Expr *>(); - Record.push_back(E == nullptr); - if (E) - Record.AddStmt(E); - else { - auto *Diag = DetailRecord.second.get<std::pair<SourceLocation, - StringRef> *>(); - Record.AddSourceLocation(Diag->first); - Record.AddString(Diag->second); - } - } - } - + Record.push_back(E->isSatisfied()); Code = serialization::EXPR_CONCEPT_SPECIALIZATION; } diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp index 1e10d4550ce0..dd3f0c0e3d6c 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp @@ -72,15 +72,6 @@ template<typename T> struct T2 { static constexpr bool value = sizeof(T) == 2; } static_assert(IsTypePredicate<T2>); static_assert(!IsTypePredicate<T1>); -template<typename T, typename U, typename... Ts> -concept OneOf = (Same<T, Ts> || ...); - -template<typename... X> -constexpr bool S = OneOf<X..., int, int>; - -static_assert(S<int, long, int>); -static_assert(!S<long, int, char, char>); - namespace piecewise_substitution { template <typename T> concept True = true; @@ -156,25 +147,3 @@ template<typename T> struct X { static constexpr bool a = SameSize<T>; }; static_assert(X<unsigned>::a); - -// static_assert concept diagnostics -template<typename T> -concept Large = sizeof(T) > 100; -// expected-note@-1 2{{because 'sizeof(small) > 100' (1 > 100) evaluated to false}} - -struct small { }; -static_assert(Large<small>); -// expected-error@-1 {{static_assert failed}} -// expected-note@-2 {{because 'small' does not satisfy 'Large'}} -static_assert(Large<small>, "small isn't large"); -// expected-error@-1 {{static_assert failed "small isn't large"}} -// expected-note@-2 {{because 'small' does not satisfy 'Large'}} - -// Make sure access-checking can fail a concept specialization - -class T4 { static constexpr bool f = true; }; -template<typename T> concept AccessPrivate = T{}.f; -// expected-note@-1{{because substituted constraint expression is ill-formed: 'f' is a private member of 'T4'}} -static_assert(AccessPrivate<T4>); -// expected-error@-1{{static_assert failed}} -// expected-note@-2{{because 'T4' does not satisfy 'AccessPrivate'}} diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.constr/function-templates.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.constr/function-templates.cpp deleted file mode 100644 index c1a3a27fbeac..000000000000 --- a/clang/test/CXX/temp/temp.constr/temp.constr.constr/function-templates.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s - -template<typename T> -constexpr bool is_ptr_v = false; - -template<typename T> -constexpr bool is_ptr_v<T*> = true; - -template<typename T, typename U> -constexpr bool is_same_v = false; - -template<typename T> -constexpr bool is_same_v<T, T> = true; - -template<typename T> requires is_ptr_v<T> // expected-note {{because 'is_ptr_v<int>' evaluated to false}} - // expected-note@-1{{because 'is_ptr_v<char>' evaluated to false}} -auto dereference(T t) { // expected-note {{candidate template ignored: constraints not satisfied [with T = int]}} - // expected-note@-1{{candidate template ignored: constraints not satisfied [with T = char]}} - return *t; -} - -static_assert(is_same_v<decltype(dereference<int*>(nullptr)), int>); -static_assert(is_same_v<decltype(dereference(2)), int>); // expected-error {{no matching function for call to 'dereference'}} -static_assert(is_same_v<decltype(dereference<char>('a')), char>); // expected-error {{no matching function for call to 'dereference'}} - - -template<typename T> requires T{} + T{} // expected-note {{because substituted constraint expression is ill-formed: invalid operands to binary expression ('A' and 'A')}} -auto foo(T t) { // expected-note {{candidate template ignored: constraints not satisfied [with T = A]}} - return t + t; -} - - -template<typename T> requires !((T{} - T{}) && (T{} + T{})) || false -// expected-note@-1{{because substituted constraint expression is ill-formed: invalid operands to binary expression ('A' and 'A')}} -// expected-note@-2{{and 'false' evaluated to false}} -auto bar(T t) { // expected-note {{candidate template ignored: constraints not satisfied [with T = A]}} - return t + t; -} - -struct A { }; - -static_assert(foo(A{})); // expected-error {{no matching function for call to 'foo'}} -static_assert(bar(A{})); // expected-error {{no matching function for call to 'bar'}} \ No newline at end of file diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp deleted file mode 100644 index 24caa5063a1b..000000000000 --- a/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp +++ /dev/null @@ -1,92 +0,0 @@ -// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s - -template<typename T> requires sizeof(T) >= 2 // expected-note{{because 'sizeof(char) >= 2' (1 >= 2) evaluated to false}} -struct A { - static constexpr int value = sizeof(T); -}; - -static_assert(A<int>::value == 4); -static_assert(A<char>::value == 1); // expected-error{{constraints not satisfied for class template 'A' [with T = char]}} - -template<typename T, typename U> - requires sizeof(T) != sizeof(U) // expected-note{{because 'sizeof(int) != sizeof(char [4])' (4 != 4) evaluated to false}} - && sizeof(T) >= 4 // expected-note{{because 'sizeof(char) >= 4' (1 >= 4) evaluated to false}} -constexpr int SizeDiff = sizeof(T) > sizeof(U) ? sizeof(T) - sizeof(U) : sizeof(U) - sizeof(T); - -static_assert(SizeDiff<int, char> == 3); -static_assert(SizeDiff<int, char[4]> == 0); // expected-error{{constraints not satisfied for variable template 'SizeDiff' [with T = int, U = char [4]]}} -static_assert(SizeDiff<char, int> == 3); // expected-error{{constraints not satisfied for variable template 'SizeDiff' [with T = char, U = int]}} - -template<typename... Ts> - requires ((sizeof(Ts) == 4) || ...) // expected-note{{because 'sizeof(char) == 4' (1 == 4) evaluated to false}} expected-note{{'sizeof(long long) == 4' (8 == 4) evaluated to false}} expected-note{{'sizeof(int [20]) == 4' (80 == 4) evaluated to false}} -constexpr auto SumSizes = (sizeof(Ts) + ...); - -static_assert(SumSizes<char, long long, int> == 13); -static_assert(SumSizes<char, long long, int[20]> == 89); // expected-error{{constraints not satisfied for variable template 'SumSizes' [with Ts = <char, long long, int [20]>]}} - -template<typename T> -concept IsBig = sizeof(T) > 100; // expected-note{{because 'sizeof(int) > 100' (4 > 100) evaluated to false}} - -template<typename T> - requires IsBig<T> // expected-note{{'int' does not satisfy 'IsBig'}} -using BigPtr = T*; - -static_assert(sizeof(BigPtr<int>)); // expected-error{{constraints not satisfied for alias template 'BigPtr' [with T = int]}}}} - -template<typename T> requires T::value // expected-note{{because substituted constraint expression is ill-formed: type 'int' cannot be used prior to '::' because it has no members}} -struct S { static constexpr bool value = true; }; - -struct S2 { static constexpr bool value = true; }; - -static_assert(S<int>::value); // expected-error{{constraints not satisfied for class template 'S' [with T = int]}} -static_assert(S<S2>::value); - -template<typename T> -struct AA -{ - template<typename U> requires sizeof(U) == sizeof(T) // expected-note{{because 'sizeof(int [2]) == sizeof(int)' (8 == 4) evaluated to false}} - struct B - { - static constexpr int a = 0; - }; - - template<typename U> requires sizeof(U) == sizeof(T) // expected-note{{because 'sizeof(int [2]) == sizeof(int)' (8 == 4) evaluated to false}} - static constexpr int b = 1; - - template<typename U> requires sizeof(U) == sizeof(T) // expected-note{{because 'sizeof(int [2]) == sizeof(int)' (8 == 4) evaluated to false}} - static constexpr int getB() { // expected-note{{candidate template ignored: constraints not satisfied [with U = int [2]]}} - return 2; - } - - static auto foo() - { - return B<T[2]>::a; // expected-error{{constraints not satisfied for class template 'B' [with U = int [2]]}} - } - - static auto foo1() - { - return b<T[2]>; // expected-error{{constraints not satisfied for variable template 'b' [with U = int [2]]}} - } - - static auto foo2() - { - return AA<T>::getB<T[2]>(); // expected-error{{no matching function for call to 'getB'}} - } -}; - -constexpr auto x = AA<int>::foo(); // expected-note{{in instantiation of member function 'AA<int>::foo' requested here}} -constexpr auto x1 = AA<int>::foo1(); // expected-note{{in instantiation of member function 'AA<int>::foo1' requested here}} -constexpr auto x2 = AA<int>::foo2(); // expected-note{{in instantiation of member function 'AA<int>::foo2' requested here}} - -template<typename T> -struct B { using type = typename T::type; }; // expected-error{{type 'int' cannot be used prior to '::' because it has no members}} - -template<typename T> requires B<T>::type // expected-note{{in instantiation of template class 'B<int>' requested here}} - // expected-note@-1{{while substituting template arguments into constraint expression here}} -struct C { }; - -template<typename T> requires T{} // expected-error{{atomic constraint must be of type 'bool' (found 'int')}} -struct D { }; - -static_assert(C<int>{}); // expected-note{{while checking constraint satisfaction for template 'C<int>' required here}} -static_assert(D<int>{}); // expected-note{{while checking constraint satisfaction for template 'D<int>' required here}} \ No newline at end of file diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp deleted file mode 100644 index 47bd2a550769..000000000000 --- a/clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s - -namespace class_templates -{ - template<typename T, typename U> requires sizeof(T) >= 4 // expected-note {{because 'sizeof(char) >= 4' (1 >= 4) evaluated to false}} - struct is_same { static constexpr bool value = false; }; - - template<typename T> requires sizeof(T*) >= 4 && sizeof(T) >= 4 - struct is_same<T*, T*> { static constexpr bool value = true; }; - - static_assert(!is_same<char*, char*>::value); - static_assert(!is_same<short*, short*>::value); - static_assert(is_same<int*, int*>::value); - static_assert(is_same<char, char>::value); // expected-error {{constraints not satisfied for class template 'is_same' [with T = char, U = char]}} - - template<typename T> - struct A { using type = typename T::type; }; // expected-error{{type 'int *' cannot be used prior to '::' because it has no members}} - - template<typename T> - struct B {}; - - template<typename T> requires A<T>::type // expected-note{{in instantiation of template class 'class_templates::A<int *>' requested here}} - // expected-note@-1{{while substituting template arguments into constraint expression here}} - struct B<T*> {}; - - template<typename T> requires T{} // expected-error{{atomic constraint must be of type 'bool' (found 'int')}} - struct B<T**> {}; - - static_assert((B<int**>{}, true)); // expected-note{{while checking constraint satisfaction for class template partial specialization 'B<int *>' required here}} - // expected-note@-1{{while checking constraint satisfaction for class template partial specialization 'B<int>' required here}} - // expected-note@-2{{during template argument deduction for class template partial specialization 'B<T *>' [with T = int *]}} - // expected-note@-3{{during template argument deduction for class template partial specialization 'B<T **>' [with T = int]}} - // expected-note@-4 2{{in instantiation of template class 'class_templates::B<int **>' requested here}} -} - -namespace variable_templates -{ - template<typename T, typename U> requires sizeof(T) >= 4 - constexpr bool is_same_v = false; - - template<typename T> requires sizeof(T*) >= 4 && sizeof(T) >= 4 - constexpr bool is_same_v<T*, T*> = true; - - static_assert(!is_same_v<char*, char*>); - static_assert(!is_same_v<short*, short*>); - static_assert(is_same_v<int*, int*>); - - template<typename T> - struct A { using type = typename T::type; }; // expected-error{{type 'int *' cannot be used prior to '::' because it has no members}} - - template<typename T> - constexpr bool v1 = false; - - template<typename T> requires A<T>::type // expected-note{{in instantiation of template class 'variable_templates::A<int *>' requested here}} - // expected-note@-1{{while substituting template arguments into constraint expression here}} - constexpr bool v1<T*> = true; - - template<typename T> requires T{} // expected-error{{atomic constraint must be of type 'bool' (found 'int')}} - constexpr bool v1<T**> = true; - - static_assert(v1<int**>); // expected-note{{while checking constraint satisfaction for variable template partial specialization 'v1<int *>' required here}} - // expected-note@-1{{while checking constraint satisfaction for variable template partial specialization 'v1<int>' required here}} - // expected-note@-2{{during template argument deduction for variable template partial specialization 'v1<T *>' [with T = int *]}} - // expected-note@-3{{during template argument deduction for variable template partial specialization 'v1<T **>' [with T = int]}} - // expected-error@-4{{static_assert failed due to requirement 'v1<int **>'}} - -} \ No newline at end of file _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits