r374903 - [Concepts] Concept Specialization Expressions

Saar Raz via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 15 08:47:10 PDT 2019


Thanks, fixed in 374907.

On Tue, Oct 15, 2019 at 6:38 PM Benjamin Kramer <benny.kra at gmail.com> wrote:

>
>
> On Tue, Oct 15, 2019 at 5:21 PM Saar Raz via cfe-commits <
> cfe-commits at lists.llvm.org> wrote:
>
>> Author: saar.raz
>> Date: Tue Oct 15 08:24:26 2019
>> New Revision: 374903
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=374903&view=rev
>> Log:
>> [Concepts] Concept Specialization Expressions
>>
>> Part of C++20 Concepts implementation effort. Added Concept
>> Specialization Expressions that are created when a concept is refe$
>>
>> D41217 on Phabricator.
>>
>> (recommit after fixing failing Parser test on windows)
>>
>>
>> Added:
>>     cfe/trunk/lib/Sema/SemaConcept.cpp
>>     cfe/trunk/test/CXX/expr/expr.prim/expr.prim.id/
>>     cfe/trunk/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp
>>     cfe/trunk/test/CXX/temp/temp.constr/
>>     cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/
>>
>> cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
>>     cfe/trunk/test/PCH/cxx2a-concept-specialization-expr.cpp
>> Removed:
>>     cfe/trunk/test/CXX/concepts-ts/
>> Modified:
>>     cfe/trunk/include/clang/AST/ExprCXX.h
>>     cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
>>     cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>>     cfe/trunk/include/clang/Basic/StmtNodes.td
>>     cfe/trunk/include/clang/Sema/Sema.h
>>     cfe/trunk/include/clang/Serialization/ASTBitCodes.h
>>     cfe/trunk/lib/AST/Expr.cpp
>>     cfe/trunk/lib/AST/ExprCXX.cpp
>>     cfe/trunk/lib/AST/ExprClassification.cpp
>>     cfe/trunk/lib/AST/ExprConstant.cpp
>>     cfe/trunk/lib/AST/ItaniumMangle.cpp
>>     cfe/trunk/lib/AST/StmtPrinter.cpp
>>     cfe/trunk/lib/AST/StmtProfile.cpp
>>     cfe/trunk/lib/CodeGen/CGExprScalar.cpp
>>     cfe/trunk/lib/Frontend/FrontendActions.cpp
>>     cfe/trunk/lib/Parse/ParseExpr.cpp
>>     cfe/trunk/lib/Sema/CMakeLists.txt
>>     cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
>>     cfe/trunk/lib/Sema/SemaTemplate.cpp
>>     cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
>>     cfe/trunk/lib/Sema/TreeTransform.h
>>     cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
>>     cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
>>     cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
>>     cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp
>>     cfe/trunk/tools/libclang/CXCursor.cpp
>>
>> Modified: cfe/trunk/include/clang/AST/ExprCXX.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/include/clang/AST/ExprCXX.h (original)
>> +++ cfe/trunk/include/clang/AST/ExprCXX.h Tue Oct 15 08:24:26 2019
>> @@ -17,6 +17,7 @@
>>  #include "clang/AST/Decl.h"
>>  #include "clang/AST/DeclBase.h"
>>  #include "clang/AST/DeclCXX.h"
>> +#include "clang/AST/DeclTemplate.h"
>>  #include "clang/AST/DeclarationName.h"
>>  #include "clang/AST/Expr.h"
>>  #include "clang/AST/NestedNameSpecifier.h"
>> @@ -56,6 +57,7 @@ class IdentifierInfo;
>>  class LambdaCapture;
>>  class NonTypeTemplateParmDecl;
>>  class TemplateParameterList;
>> +class Sema;
>>
>>
>>  //===--------------------------------------------------------------------===//
>>  // C++ Expressions.
>> @@ -4750,6 +4752,125 @@ public:
>>    }
>>  };
>>
>> +/// \brief Represents the specialization of a concept - evaluates to a
>> prvalue
>> +/// of type bool.
>> +///
>> +/// According to C++2a [expr.prim.id]p3 an id-expression that denotes
>> the
>> +/// specialization of a concept results in a prvalue of type bool.
>> +class ConceptSpecializationExpr final : public Expr,
>> +      private llvm::TrailingObjects<ConceptSpecializationExpr,
>> +                                    TemplateArgument> {
>> +  friend class ASTStmtReader;
>> +  friend TrailingObjects;
>> +
>> +  // \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 location of the concept name in the expression.
>> +  SourceLocation ConceptNameLoc;
>> +
>> +  /// \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, 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.
>> +  const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
>> +
>> +  /// \brief The number of template arguments in the tail-allocated list
>> of
>> +  /// converted template arguments.
>> +  unsigned NumTemplateArgs;
>> +
>> +  ConceptSpecializationExpr(ASTContext &C, NestedNameSpecifierLoc NNS,
>> +                            SourceLocation TemplateKWLoc,
>> +                            SourceLocation ConceptNameLoc, NamedDecl
>> *FoundDecl,
>> +                            ConceptDecl *NamedConcept,
>> +                            const ASTTemplateArgumentListInfo
>> *ArgsAsWritten,
>> +                            ArrayRef<TemplateArgument> ConvertedArgs,
>> +                            Optional<bool> IsSatisfied);
>> +
>> +  ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs);
>> +
>> +public:
>> +
>> +  static ConceptSpecializationExpr *
>> +  Create(ASTContext &C, NestedNameSpecifierLoc NNS,
>> +         SourceLocation TemplateKWLoc, SourceLocation ConceptNameLoc,
>> +         NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
>> +         const ASTTemplateArgumentListInfo *ArgsAsWritten,
>> +         ArrayRef<TemplateArgument> ConvertedArgs, Optional<bool>
>> IsSatisfied);
>> +
>> +  static ConceptSpecializationExpr *
>> +  Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs);
>> +
>> +  const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
>> +    return NestedNameSpec;
>> +  }
>> +
>> +  NamedDecl *getFoundDecl() const {
>> +    return FoundDecl;
>> +  }
>> +
>> +  ConceptDecl *getNamedConcept() const {
>> +    return NamedConcept.getPointer();
>> +  }
>> +
>> +  ArrayRef<TemplateArgument> getTemplateArguments() const {
>> +    return
>> ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(),
>> +                                      NumTemplateArgs);
>> +  }
>> +
>> +  const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
>> +    return ArgsAsWritten;
>> +  }
>> +
>> +  /// \brief Set new template arguments for this concept specialization.
>> +  void setTemplateArguments(const ASTTemplateArgumentListInfo
>> *ArgsAsWritten,
>> +                            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!
>> +  bool isSatisfied() const {
>> +    assert(!isValueDependent()
>> +           && "isSatisfied called on a dependent
>> ConceptSpecializationExpr");
>> +    return NamedConcept.getInt();
>> +  }
>> +
>> +  SourceLocation getConceptNameLoc() const { return ConceptNameLoc; }
>> +
>> +  SourceLocation getTemplateKWLoc() const { return TemplateKWLoc; }
>> +
>> +  static bool classof(const Stmt *T) {
>> +    return T->getStmtClass() == ConceptSpecializationExprClass;
>> +  }
>> +
>> +  SourceLocation getBeginLoc() const LLVM_READONLY { return
>> ConceptNameLoc; }
>> +  SourceLocation getEndLoc() const LLVM_READONLY {
>> +    return ArgsAsWritten->RAngleLoc;
>> +  }
>> +
>> +  // Iterators
>> +  child_range children() {
>> +    return child_range(child_iterator(), child_iterator());
>> +  }
>> +  const_child_range children() const {
>> +    return const_child_range(const_child_iterator(),
>> const_child_iterator());
>> +  }
>> +};
>> +
>>  } // namespace clang
>>
>>  #endif // LLVM_CLANG_AST_EXPRCXX_H
>>
>> Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
>> +++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Tue Oct 15 08:24:26
>> 2019
>> @@ -2659,6 +2659,12 @@ DEF_TRAVERSE_STMT(CoyieldExpr, {
>>    }
>>  })
>>
>> +DEF_TRAVERSE_STMT(ConceptSpecializationExpr, {
>> +  TRY_TO(TraverseTemplateArgumentLocsHelper(
>> +          S->getTemplateArgsAsWritten()->getTemplateArgs(),
>> +          S->getTemplateArgsAsWritten()->NumTemplateArgs));
>> +})
>> +
>>  // These literals (all of them) do not need any action.
>>  DEF_TRAVERSE_STMT(IntegerLiteral, {})
>>  DEF_TRAVERSE_STMT(FixedPointLiteral, {})
>>
>> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
>> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Oct 15
>> 08:24:26 2019
>> @@ -2526,8 +2526,6 @@ def note_private_extern : Note<
>>    "use __attribute__((visibility(\"hidden\"))) attribute instead">;
>>
>>  // C++ Concepts
>> -def err_concept_initialized_with_non_bool_type : Error<
>> -  "constraint expression must be of type 'bool' but is of type %0">;
>>  def err_concept_decls_may_only_appear_in_global_namespace_scope : Error<
>>    "concept declarations may only appear in global or namespace scope">;
>>  def err_concept_no_parameters : Error<
>> @@ -2539,6 +2537,11 @@ def err_concept_no_associated_constraint
>>    "concept cannot have associated constraints">;
>>  def err_concept_not_implemented : Error<
>>    "sorry, unimplemented concepts feature %0 used">;
>> +def err_non_constant_constraint_expression : Error<
>> +  "substitution into constraint expression resulted in a non-constant "
>> +  "expression">;
>> +def err_non_bool_atomic_constraint : Error<
>> +  "atomic constraint must be of type 'bool' (found %0)">;
>>
>>  def err_template_different_associated_constraints : Error<
>>    "associated constraints differ in template redeclaration">;
>> @@ -4496,6 +4499,10 @@ def note_prior_template_arg_substitution
>>    " template parameter%1 %2">;
>>  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_constraint_substitution_here : Note<
>> +  "while substituting template arguments into constraint expression
>> here">;
>>  def note_instantiation_contexts_suppressed : Note<
>>    "(skipping %0 context%s0 in backtrace; use
>> -ftemplate-backtrace-limit=0 to "
>>    "see all)">;
>>
>> Modified: cfe/trunk/include/clang/Basic/StmtNodes.td
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/StmtNodes.td?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/include/clang/Basic/StmtNodes.td (original)
>> +++ cfe/trunk/include/clang/Basic/StmtNodes.td Tue Oct 15 08:24:26 2019
>> @@ -163,6 +163,9 @@ def CoawaitExpr : DStmt<CoroutineSuspend
>>  def DependentCoawaitExpr : DStmt<Expr>;
>>  def CoyieldExpr : DStmt<CoroutineSuspendExpr>;
>>
>> +// C++2a Concepts expressions
>> +def ConceptSpecializationExpr : DStmt<Expr>;
>> +
>>  // Obj-C Expressions.
>>  def ObjCStringLiteral : DStmt<Expr>;
>>  def ObjCBoxedExpr : DStmt<Expr>;
>>
>> Modified: cfe/trunk/include/clang/Sema/Sema.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/include/clang/Sema/Sema.h (original)
>> +++ cfe/trunk/include/clang/Sema/Sema.h Tue Oct 15 08:24:26 2019
>> @@ -6047,7 +6047,16 @@ public:
>>                                             CXXConversionDecl *Conv,
>>                                             Expr *Src);
>>
>> -  // ParseObjCStringLiteral - Parse Objective-C string literals.
>> +  /// Check whether the given expression is a valid constraint
>> expression.
>> +  /// 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);
>> +
>> +    // ParseObjCStringLiteral - Parse Objective-C string literals.
>>    ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
>>                                      ArrayRef<Expr *> Strings);
>>
>> @@ -6718,9 +6727,9 @@ public:
>>
>>    ExprResult
>>    CheckConceptTemplateId(const CXXScopeSpec &SS,
>> -                         const DeclarationNameInfo &NameInfo,
>> -                         ConceptDecl *Template,
>> -                         SourceLocation TemplateLoc,
>> +                         SourceLocation TemplateKWLoc,
>> +                         SourceLocation ConceptNameLoc, NamedDecl
>> *FoundDecl,
>> +                         ConceptDecl *NamedConcept,
>>                           const TemplateArgumentListInfo *TemplateArgs);
>>
>>    void diagnoseMissingTemplateArguments(TemplateName Name,
>> SourceLocation Loc);
>> @@ -7639,6 +7648,15 @@ public:
>>        /// member).
>>        DefiningSynthesizedFunction,
>>
>> +      // We are checking the constraints associated with a constrained
>> entity or
>> +      // the constraint expression of a concept. This includes the
>> checks that
>> +      // atomic constraints have the type 'bool' and that they can be
>> constant
>> +      // evaluated.
>> +      ConstraintsCheck,
>> +
>> +      // We are substituting template arguments into a constraint
>> expression.
>> +      ConstraintSubstitution,
>> +
>>        /// Added for Template instantiation observation.
>>        /// Memoization means we are _not_ instantiating a template because
>>        /// it is already instantiated (but we entered a context where we
>> @@ -7899,6 +7917,23 @@ public:
>>                            ArrayRef<TemplateArgument> TemplateArgs,
>>                            SourceRange InstantiationRange);
>>
>> +    struct ConstraintsCheck {};
>> +    /// \brief Note that we are checking the constraints associated with
>> some
>> +    /// constrained entity (a concept declaration or a template with
>> associated
>> +    /// constraints).
>> +    InstantiatingTemplate(Sema &SemaRef, SourceLocation
>> PointOfInstantiation,
>> +                          ConstraintsCheck, TemplateDecl *Template,
>> +                          ArrayRef<TemplateArgument> TemplateArgs,
>> +                          SourceRange InstantiationRange);
>> +
>> +    struct ConstraintSubstitution {};
>> +    /// \brief Note that we are checking a constraint expression
>> associated
>> +    /// with a template declaration or as part of the satisfaction check
>> of a
>> +    /// concept.
>> +    InstantiatingTemplate(Sema &SemaRef, SourceLocation
>> PointOfInstantiation,
>> +                          ConstraintSubstitution, TemplateDecl *Template,
>> +                          sema::TemplateDeductionInfo &DeductionInfo,
>> +                          SourceRange InstantiationRange);
>>
>>      /// Note that we have finished instantiating this template.
>>      void Clear();
>>
>> Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
>> +++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Tue Oct 15
>> 08:24:26 2019
>> @@ -1915,6 +1915,7 @@ namespace serialization {
>>        EXPR_FUNCTION_PARM_PACK,    // FunctionParmPackExpr
>>        EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr
>>        EXPR_CXX_FOLD,              // CXXFoldExpr
>> +      EXPR_CONCEPT_SPECIALIZATION,// ConceptSpecializationExpr
>>
>>        // CUDA
>>        EXPR_CUDA_KERNEL_CALL,       // CUDAKernelCallExpr
>>
>> Modified: cfe/trunk/lib/AST/Expr.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/AST/Expr.cpp (original)
>> +++ cfe/trunk/lib/AST/Expr.cpp Tue Oct 15 08:24:26 2019
>> @@ -3403,6 +3403,7 @@ bool Expr::HasSideEffects(const ASTConte
>>    case CXXUuidofExprClass:
>>    case OpaqueValueExprClass:
>>    case SourceLocExprClass:
>> +  case ConceptSpecializationExprClass:
>>      // These never have a side-effect.
>>      return false;
>>
>>
>> Modified: cfe/trunk/lib/AST/ExprCXX.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/AST/ExprCXX.cpp (original)
>> +++ cfe/trunk/lib/AST/ExprCXX.cpp Tue Oct 15 08:24:26 2019
>> @@ -28,6 +28,9 @@
>>  #include "clang/Basic/OperatorKinds.h"
>>  #include "clang/Basic/SourceLocation.h"
>>  #include "clang/Basic/Specifiers.h"
>> +#include "clang/Sema/Template.h"
>> +#include "clang/Sema/SemaDiagnostic.h"
>> +#include "clang/Sema/Sema.h"
>>
>
> These includes are unused and invalid because lib/AST cannot depend on
> lib/Sema. Please remove them asap.
>
>
>>  #include "llvm/ADT/ArrayRef.h"
>>  #include "llvm/Support/Casting.h"
>>  #include "llvm/Support/ErrorHandling.h"
>> @@ -1680,3 +1683,82 @@ CUDAKernelCallExpr *CUDAKernelCallExpr::
>>                             alignof(CUDAKernelCallExpr));
>>    return new (Mem) CUDAKernelCallExpr(NumArgs, Empty);
>>  }
>> +
>> +ConceptSpecializationExpr::ConceptSpecializationExpr(ASTContext &C,
>> +    NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
>> +    SourceLocation ConceptNameLoc, NamedDecl *FoundDecl,
>> +    ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo
>> *ArgsAsWritten,
>> +    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=*/!IsSatisfied.hasValue(),
>> +           /*InstantiationDependent=*/false,
>> +           /*ContainsUnexpandedParameterPacks=*/false),
>> +      NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc),
>> +      ConceptNameLoc(ConceptNameLoc), FoundDecl(FoundDecl),
>> +      NamedConcept(NamedConcept, IsSatisfied ? *IsSatisfied : true),
>> +      NumTemplateArgs(ConvertedArgs.size()) {
>> +
>> +  setTemplateArguments(ArgsAsWritten, ConvertedArgs);
>> +}
>> +
>> +ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
>> +    unsigned NumTemplateArgs)
>> +    : Expr(ConceptSpecializationExprClass, Empty),
>> +      NumTemplateArgs(NumTemplateArgs) { }
>> +
>> +void ConceptSpecializationExpr::setTemplateArguments(
>> +    const ASTTemplateArgumentListInfo *ArgsAsWritten,
>> +    ArrayRef<TemplateArgument> Converted) {
>> +  assert(Converted.size() == NumTemplateArgs);
>> +  assert(!this->ArgsAsWritten && "setTemplateArguments can only be used
>> once");
>> +  this->ArgsAsWritten = ArgsAsWritten;
>> +  std::uninitialized_copy(Converted.begin(), Converted.end(),
>> +                          getTrailingObjects<TemplateArgument>());
>> +  bool IsInstantiationDependent = false;
>> +  bool ContainsUnexpandedParameterPack = false;
>> +  for (const TemplateArgumentLoc& LocInfo : ArgsAsWritten->arguments()) {
>> +    if (LocInfo.getArgument().isInstantiationDependent())
>> +      IsInstantiationDependent = true;
>> +    if (LocInfo.getArgument().containsUnexpandedParameterPack())
>> +      ContainsUnexpandedParameterPack = true;
>> +    if (ContainsUnexpandedParameterPack && IsInstantiationDependent)
>> +      break;
>> +  }
>> +
>> +  // Currently guaranteed by the fact concepts can only be at
>> namespace-scope.
>> +  assert(!NestedNameSpec ||
>> +
>>  (!NestedNameSpec.getNestedNameSpecifier()->isInstantiationDependent() &&
>> +          !NestedNameSpec.getNestedNameSpecifier()
>> +              ->containsUnexpandedParameterPack()));
>> +  setInstantiationDependent(IsInstantiationDependent);
>> +  setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack);
>> +  assert((!isValueDependent() || isInstantiationDependent()) &&
>> +         "should not be value-dependent");
>> +}
>> +
>> +ConceptSpecializationExpr *
>> +ConceptSpecializationExpr::Create(ASTContext &C, NestedNameSpecifierLoc
>> NNS,
>> +                                  SourceLocation TemplateKWLoc,
>> +                                  SourceLocation ConceptNameLoc,
>> +                                  NamedDecl *FoundDecl,
>> +                                  ConceptDecl *NamedConcept,
>> +                               const ASTTemplateArgumentListInfo
>> *ArgsAsWritten,
>> +                                  ArrayRef<TemplateArgument>
>> ConvertedArgs,
>> +                                  Optional<bool> IsSatisfied) {
>> +  void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
>> +                                ConvertedArgs.size()));
>> +  return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc,
>> +                                                ConceptNameLoc,
>> FoundDecl,
>> +                                                NamedConcept,
>> ArgsAsWritten,
>> +                                                ConvertedArgs,
>> IsSatisfied);
>> +}
>> +
>> +ConceptSpecializationExpr *
>> +ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty,
>> +                                  unsigned NumTemplateArgs) {
>> +  void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
>> +                                NumTemplateArgs));
>> +  return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs);
>> +}
>> \ No newline at end of file
>>
>> Modified: cfe/trunk/lib/AST/ExprClassification.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprClassification.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/AST/ExprClassification.cpp (original)
>> +++ cfe/trunk/lib/AST/ExprClassification.cpp Tue Oct 15 08:24:26 2019
>> @@ -192,6 +192,7 @@ static Cl::Kinds ClassifyInternal(ASTCon
>>    case Expr::NoInitExprClass:
>>    case Expr::DesignatedInitUpdateExprClass:
>>    case Expr::SourceLocExprClass:
>> +  case Expr::ConceptSpecializationExprClass:
>>      return Cl::CL_PRValue;
>>
>>    case Expr::ConstantExprClass:
>>
>> Modified: cfe/trunk/lib/AST/ExprConstant.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
>> +++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Oct 15 08:24:26 2019
>> @@ -9768,6 +9768,7 @@ public:
>>    bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);
>>    bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
>>    bool VisitSourceLocExpr(const SourceLocExpr *E);
>> +  bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr
>> *E);
>>    // FIXME: Missing: array subscript of vector, member of vector
>>  };
>>
>> @@ -12250,6 +12251,12 @@ bool IntExprEvaluator::VisitCXXNoexceptE
>>    return Success(E->getValue(), E);
>>  }
>>
>> +bool IntExprEvaluator::VisitConceptSpecializationExpr(
>> +       const ConceptSpecializationExpr *E) {
>> +  return Success(E->isSatisfied(), E);
>> +}
>> +
>> +
>>  bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E)
>> {
>>    switch (E->getOpcode()) {
>>      default:
>> @@ -13923,6 +13930,7 @@ static ICEDiag CheckICE(const Expr* E, c
>>    case Expr::CXXBoolLiteralExprClass:
>>    case Expr::CXXScalarValueInitExprClass:
>>    case Expr::TypeTraitExprClass:
>> +  case Expr::ConceptSpecializationExprClass:
>>    case Expr::ArrayTypeTraitExprClass:
>>    case Expr::ExpressionTraitExprClass:
>>    case Expr::CXXNoexceptExprClass:
>>
>> Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
>> +++ cfe/trunk/lib/AST/ItaniumMangle.cpp Tue Oct 15 08:24:26 2019
>> @@ -3658,6 +3658,7 @@ recurse:
>>    case Expr::ConvertVectorExprClass:
>>    case Expr::StmtExprClass:
>>    case Expr::TypeTraitExprClass:
>> +  case Expr::ConceptSpecializationExprClass:
>>    case Expr::ArrayTypeTraitExprClass:
>>    case Expr::ExpressionTraitExprClass:
>>    case Expr::VAArgExprClass:
>>
>> Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
>> +++ cfe/trunk/lib/AST/StmtPrinter.cpp Tue Oct 15 08:24:26 2019
>> @@ -2231,6 +2231,17 @@ void StmtPrinter::VisitCXXFoldExpr(CXXFo
>>    OS << ")";
>>  }
>>
>> +void
>> StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
>> +  NestedNameSpecifierLoc NNS = E->getNestedNameSpecifierLoc();
>> +  if (NNS)
>> +    NNS.getNestedNameSpecifier()->print(OS, Policy);
>> +  if (E->getTemplateKWLoc().isValid())
>> +    OS << "template ";
>> +  OS << E->getFoundDecl()->getName();
>> +  printTemplateArgumentList(OS,
>> E->getTemplateArgsAsWritten()->arguments(),
>> +                            Policy);
>> +}
>> +
>>  // C++ Coroutines TS
>>
>>  void StmtPrinter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
>>
>> Modified: cfe/trunk/lib/AST/StmtProfile.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/AST/StmtProfile.cpp (original)
>> +++ cfe/trunk/lib/AST/StmtProfile.cpp Tue Oct 15 08:24:26 2019
>> @@ -1309,6 +1309,14 @@ void StmtProfiler::VisitAtomicExpr(const
>>    ID.AddInteger(S->getOp());
>>  }
>>
>> +void StmtProfiler::VisitConceptSpecializationExpr(
>> +                                           const
>> ConceptSpecializationExpr *S) {
>> +  VisitExpr(S);
>> +  VisitDecl(S->getFoundDecl());
>> +
>> VisitTemplateArguments(S->getTemplateArgsAsWritten()->getTemplateArgs(),
>> +                         S->getTemplateArgsAsWritten()->NumTemplateArgs);
>> +}
>> +
>>  static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S,
>>                                            UnaryOperatorKind &UnaryOp,
>>                                            BinaryOperatorKind &BinaryOp) {
>>
>> Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
>> +++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Tue Oct 15 08:24:26 2019
>> @@ -673,6 +673,10 @@ public:
>>      return llvm::ConstantInt::get(ConvertType(E->getType()),
>> E->getValue());
>>    }
>>
>> +  Value *VisitConceptSpecializationExpr(const ConceptSpecializationExpr
>> *E) {
>> +    return Builder.getInt1(E->isSatisfied());
>> +  }
>> +
>>    Value *VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) {
>>      return llvm::ConstantInt::get(Builder.getInt32Ty(), E->getValue());
>>    }
>>
>> Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/Frontend/FrontendActions.cpp (original)
>> +++ cfe/trunk/lib/Frontend/FrontendActions.cpp Tue Oct 15 08:24:26 2019
>> @@ -417,6 +417,10 @@ private:
>>        return "DefiningSynthesizedFunction";
>>      case CodeSynthesisContext::Memoization:
>>        return "Memoization";
>> +    case CodeSynthesisContext::ConstraintsCheck:
>> +      return "ConstraintsCheck";
>> +    case CodeSynthesisContext::ConstraintSubstitution:
>> +      return "ConstraintSubstitution";
>>      }
>>      return "";
>>    }
>>
>> Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
>> +++ cfe/trunk/lib/Parse/ParseExpr.cpp Tue Oct 15 08:24:26 2019
>> @@ -228,18 +228,16 @@ ExprResult Parser::ParseCaseExpression(S
>>  /// Parse a constraint-expression.
>>  ///
>>  /// \verbatim
>> -///       constraint-expression: [Concepts TS temp.constr.decl p1]
>> +///       constraint-expression: C++2a[temp.constr.decl]p1
>>  ///         logical-or-expression
>>  /// \endverbatim
>>  ExprResult Parser::ParseConstraintExpression() {
>> -  // FIXME: this may erroneously consume a function-body as the braced
>> -  // initializer list of a compound literal
>> -  //
>> -  // FIXME: this may erroneously consume a parenthesized rvalue reference
>> -  // declarator as a parenthesized address-of-label expression
>> +  EnterExpressionEvaluationContext ConstantEvaluated(
>> +      Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
>>    ExprResult LHS(ParseCastExpression(/*isUnaryExpression=*/false));
>>    ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr));
>> -
>> +  if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get()))
>> +    return ExprError();
>>    return Res;
>>  }
>>
>>
>> Modified: cfe/trunk/lib/Sema/CMakeLists.txt
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CMakeLists.txt?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/Sema/CMakeLists.txt (original)
>> +++ cfe/trunk/lib/Sema/CMakeLists.txt Tue Oct 15 08:24:26 2019
>> @@ -32,6 +32,7 @@ add_clang_library(clangSema
>>    SemaCast.cpp
>>    SemaChecking.cpp
>>    SemaCodeComplete.cpp
>> +  SemaConcept.cpp
>>    SemaConsumer.cpp
>>    SemaCoroutine.cpp
>>    SemaCUDA.cpp
>>
>> Added: cfe/trunk/lib/Sema/SemaConcept.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaConcept.cpp?rev=374903&view=auto
>>
>> ==============================================================================
>> --- cfe/trunk/lib/Sema/SemaConcept.cpp (added)
>> +++ cfe/trunk/lib/Sema/SemaConcept.cpp Tue Oct 15 08:24:26 2019
>> @@ -0,0 +1,125 @@
>> +//===-- SemaConcept.cpp - Semantic Analysis for Constraints and Concepts
>> --===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +//
>> +//  This file implements semantic analysis for C++ constraints and
>> concepts.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#include "clang/Sema/Sema.h"
>> +#include "clang/Sema/SemaDiagnostic.h"
>> +#include "clang/Sema/TemplateDeduction.h"
>> +#include "clang/Sema/Template.h"
>> +#include "clang/AST/ExprCXX.h"
>> +using namespace clang;
>> +using namespace sema;
>> +
>> +bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) {
>> +  // C++2a [temp.constr.atomic]p1
>> +  // ..E shall be a constant expression of type bool.
>> +
>> +  ConstraintExpression = ConstraintExpression->IgnoreParenImpCasts();
>> +
>> +  if (auto *BinOp = dyn_cast<BinaryOperator>(ConstraintExpression)) {
>> +    if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr)
>> +      return CheckConstraintExpression(BinOp->getLHS()) &&
>> +             CheckConstraintExpression(BinOp->getRHS());
>> +  } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpression))
>> +    return CheckConstraintExpression(C->getSubExpr());
>> +
>> +  // An atomic constraint!
>> +  if (ConstraintExpression->isTypeDependent())
>> +    return true;
>> +
>> +  QualType Type = ConstraintExpression->getType();
>> +  if (!Context.hasSameUnqualifiedType(Type, Context.BoolTy)) {
>> +    Diag(ConstraintExpression->getExprLoc(),
>> +         diag::err_non_bool_atomic_constraint) << Type
>> +        << ConstraintExpression->getSourceRange();
>> +    return false;
>> +  }
>> +  return true;
>> +}
>> +
>> +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) {
>> +      if (CalculateConstraintSatisfaction(NamedConcept, MLTAL,
>> BO->getLHS(),
>> +                                          IsSatisfied))
>> +        return true;
>> +      if (!IsSatisfied)
>> +        return false;
>> +      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(NamedConcept, MLTAL,
>> BO->getRHS(),
>> +                                             IsSatisfied);
>> +    }
>> +  }
>> +  else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr))
>> +    return CalculateConstraintSatisfaction(NamedConcept, MLTAL,
>> C->getSubExpr(),
>> +                                           IsSatisfied);
>> +
>> +  EnterExpressionEvaluationContext ConstantEvaluated(
>> +      *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);
>> +
>> +    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;
>> +    }
>> +  }
>> +
>> +  if (!CheckConstraintExpression(E.get()))
>> +    return true;
>> +
>> +  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;
>> +  }
>> +
>> +  IsSatisfied = EvalResult.Val.getInt().getBoolValue();
>> +
>> +  return false;
>> +}
>>
>> Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Tue Oct 15 08:24:26 2019
>> @@ -1314,6 +1314,7 @@ CanThrowResult Sema::canThrow(const Expr
>>    case Expr::SizeOfPackExprClass:
>>    case Expr::StringLiteralClass:
>>    case Expr::SourceLocExprClass:
>> +  case Expr::ConceptSpecializationExprClass:
>>      // These expressions can never throw.
>>      return CT_Cannot;
>>
>>
>> Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Oct 15 08:24:26 2019
>> @@ -4271,14 +4271,47 @@ void Sema::diagnoseMissingTemplateArgume
>>
>>  ExprResult
>>  Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
>> -                             const DeclarationNameInfo &NameInfo,
>> -                             ConceptDecl *Template,
>> -                             SourceLocation TemplateLoc,
>> +                             SourceLocation TemplateKWLoc,
>> +                             SourceLocation ConceptNameLoc,
>> +                             NamedDecl *FoundDecl,
>> +                             ConceptDecl *NamedConcept,
>>                               const TemplateArgumentListInfo
>> *TemplateArgs) {
>> -  // TODO: Do concept specialization here.
>> -  Diag(NameInfo.getBeginLoc(), diag::err_concept_not_implemented) <<
>> -    "concept specialization";
>> -  return ExprError();
>> +  assert(NamedConcept && "A concept template id without a template?");
>> +
>> +  llvm::SmallVector<TemplateArgument, 4> Converted;
>> +  if (CheckTemplateArgumentList(NamedConcept, ConceptNameLoc,
>> +
>>  const_cast<TemplateArgumentListInfo&>(*TemplateArgs),
>> +                                /*PartialTemplateArgs=*/false, Converted,
>> +                                /*UpdateArgsWithConversion=*/false))
>> +    return ExprError();
>> +
>> +  Optional<bool> IsSatisfied;
>> +  bool AreArgsDependent = false;
>> +  for (TemplateArgument &Arg : Converted) {
>> +    if (Arg.isDependent()) {
>> +      AreArgsDependent = true;
>> +      break;
>> +    }
>> +  }
>> +  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,
>> +      IsSatisfied);
>>  }
>>
>>  ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
>> @@ -4322,9 +4355,10 @@ ExprResult Sema::BuildTemplateIdExpr(con
>>    }
>>
>>    if (R.getAsSingle<ConceptDecl>() && !AnyDependentArguments()) {
>> -    return CheckConceptTemplateId(SS, R.getLookupNameInfo(),
>> -                                  R.getAsSingle<ConceptDecl>(),
>> -                                  TemplateKWLoc, TemplateArgs);
>> +    return CheckConceptTemplateId(SS, TemplateKWLoc,
>> +                                  R.getLookupNameInfo().getBeginLoc(),
>> +                                  R.getFoundDecl(),
>> +                                  R.getAsSingle<ConceptDecl>(),
>> TemplateArgs);
>>    }
>>
>>    // We don't want lookup warnings at this point.
>> @@ -8054,20 +8088,7 @@ Decl *Sema::ActOnConceptDefinition(Scope
>>    ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name,
>>
>> TemplateParameterLists.front(),
>>                                               ConstraintExpr);
>> -
>> -  if (!ConstraintExpr->isTypeDependent() &&
>> -      ConstraintExpr->getType() != Context.BoolTy) {
>> -    // C++2a [temp.constr.atomic]p3:
>> -    // E shall be a constant expression of type bool.
>> -    // TODO: Do this check for individual atomic constraints
>> -    // and not the constraint expression. Probably should do it in
>> -    // ParseConstraintExpression.
>> -    Diag(ConstraintExpr->getSourceRange().getBegin(),
>> -        diag::err_concept_initialized_with_non_bool_type)
>> -      << ConstraintExpr->getType();
>> -    NewDecl->setInvalidDecl();
>> -  }
>> -
>> +
>>    if (NewDecl->getAssociatedConstraints()) {
>>      // C++2a [temp.concept]p4:
>>      // A concept shall not have associated constraints.
>>
>> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Tue Oct 15 08:24:26
>> 2019
>> @@ -198,12 +198,14 @@ bool Sema::CodeSynthesisContext::isInsta
>>    case ExplicitTemplateArgumentSubstitution:
>>    case DeducedTemplateArgumentSubstitution:
>>    case PriorTemplateArgumentSubstitution:
>> +  case ConstraintsCheck:
>>      return true;
>>
>>    case DefaultTemplateArgumentChecking:
>>    case DeclaringSpecialMember:
>>    case DefiningSynthesizedFunction:
>>    case ExceptionSpecEvaluation:
>> +  case ConstraintSubstitution:
>>      return false;
>>
>>    // This function should never be called when Kind's value is
>> Memoization.
>> @@ -358,6 +360,24 @@ Sema::InstantiatingTemplate::Instantiati
>>            PointOfInstantiation, InstantiationRange, Param, Template,
>>            TemplateArgs) {}
>>
>> +Sema::InstantiatingTemplate::InstantiatingTemplate(
>> +    Sema &SemaRef, SourceLocation PointOfInstantiation,
>> +    ConstraintsCheck, TemplateDecl *Template,
>> +    ArrayRef<TemplateArgument> TemplateArgs, SourceRange
>> InstantiationRange)
>> +    : InstantiatingTemplate(
>> +          SemaRef, CodeSynthesisContext::ConstraintsCheck,
>> +          PointOfInstantiation, InstantiationRange, Template, nullptr,
>> +          TemplateArgs) {}
>> +
>> +Sema::InstantiatingTemplate::InstantiatingTemplate(
>> +    Sema &SemaRef, SourceLocation PointOfInstantiation,
>> +    ConstraintSubstitution, TemplateDecl *Template,
>> +    sema::TemplateDeductionInfo &DeductionInfo, SourceRange
>> InstantiationRange)
>> +    : InstantiatingTemplate(
>> +          SemaRef, CodeSynthesisContext::ConstraintSubstitution,
>> +          PointOfInstantiation, InstantiationRange, Template, nullptr,
>> +          {}, &DeductionInfo) {}
>> +
>>  void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
>>    Ctx.SavedInNonInstantiationSFINAEContext =
>> InNonInstantiationSFINAEContext;
>>    InNonInstantiationSFINAEContext = false;
>> @@ -664,6 +684,30 @@ void Sema::PrintInstantiationStack() {
>>
>>      case CodeSynthesisContext::Memoization:
>>        break;
>> +
>> +    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;
>> +      }
>> +      // 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)
>> +          << Active->InstantiationRange;
>> +      break;
>>      }
>>    }
>>  }
>> @@ -687,6 +731,7 @@ Optional<TemplateDeductionInfo *> Sema::
>>        LLVM_FALLTHROUGH;
>>      case CodeSynthesisContext::DefaultFunctionArgumentInstantiation:
>>      case CodeSynthesisContext::ExceptionSpecInstantiation:
>> +    case CodeSynthesisContext::ConstraintsCheck:
>>        // This is a template instantiation, so there is no SFINAE.
>>        return None;
>>
>> @@ -700,8 +745,10 @@ Optional<TemplateDeductionInfo *> Sema::
>>
>>      case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution:
>>      case CodeSynthesisContext::DeducedTemplateArgumentSubstitution:
>> -      // We're either substitution explicitly-specified template
>> arguments
>> -      // or deduced template arguments, so SFINAE applies.
>> +    case CodeSynthesisContext::ConstraintSubstitution:
>> +      // We're either substituting explicitly-specified template
>> arguments
>> +      // or deduced template arguments or a constraint expression, so
>> SFINAE
>> +      // applies.
>>        assert(Active->DeductionInfo && "Missing deduction info pointer");
>>        return Active->DeductionInfo;
>>
>>
>> Modified: cfe/trunk/lib/Sema/TreeTransform.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/Sema/TreeTransform.h (original)
>> +++ cfe/trunk/lib/Sema/TreeTransform.h Tue Oct 15 08:24:26 2019
>> @@ -3019,6 +3019,25 @@ public:
>>    ///
>>    /// By default, performs semantic analysis to build the new expression.
>>    /// Subclasses may override this routine to provide different behavior.
>> +  ExprResult RebuildConceptSpecializationExpr(NestedNameSpecifierLoc NNS,
>> +      SourceLocation TemplateKWLoc, SourceLocation ConceptNameLoc,
>> +      NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
>> +      TemplateArgumentListInfo *TALI) {
>> +    CXXScopeSpec SS;
>> +    SS.Adopt(NNS);
>> +    ExprResult Result = getSema().CheckConceptTemplateId(SS,
>> TemplateKWLoc,
>> +                                                         ConceptNameLoc,
>> +                                                         FoundDecl,
>> +                                                         NamedConcept,
>> TALI);
>> +    if (Result.isInvalid())
>> +      return ExprError();
>> +    return Result;
>> +  }
>> +
>> +    /// \brief Build a new Objective-C boxed expression.
>> +  ///
>> +  /// By default, performs semantic analysis to build the new expression.
>> +  /// Subclasses may override this routine to provide different behavior.
>>    ExprResult RebuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
>>      return getSema().BuildObjCBoxedExpr(SR, ValueExpr);
>>    }
>> @@ -11016,6 +11035,23 @@ TreeTransform<Derived>::TransformTypeTra
>>
>>  template<typename Derived>
>>  ExprResult
>> +TreeTransform<Derived>::TransformConceptSpecializationExpr(
>> +
>>  ConceptSpecializationExpr *E) {
>> +  const ASTTemplateArgumentListInfo *Old = E->getTemplateArgsAsWritten();
>> +  TemplateArgumentListInfo TransArgs(Old->LAngleLoc, Old->RAngleLoc);
>> +  if (getDerived().TransformTemplateArguments(Old->getTemplateArgs(),
>> +                                              Old->NumTemplateArgs,
>> TransArgs))
>> +    return ExprError();
>> +
>> +  return getDerived().RebuildConceptSpecializationExpr(
>> +      E->getNestedNameSpecifierLoc(), E->getTemplateKWLoc(),
>> +      E->getConceptNameLoc(), E->getFoundDecl(), E->getNamedConcept(),
>> +      &TransArgs);
>> +}
>> +
>> +
>> +template<typename Derived>
>> +ExprResult
>>  TreeTransform<Derived>::TransformArrayTypeTraitExpr(ArrayTypeTraitExpr
>> *E) {
>>    TypeSourceInfo *T =
>> getDerived().TransformType(E->getQueriedTypeSourceInfo());
>>    if (!T)
>>
>> Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
>> +++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Tue Oct 15 08:24:26 2019
>> @@ -734,6 +734,24 @@ void ASTStmtReader::VisitUnaryExprOrType
>>    E->setRParenLoc(ReadSourceLocation());
>>  }
>>
>> +void ASTStmtReader::VisitConceptSpecializationExpr(
>> +        ConceptSpecializationExpr *E) {
>> +  VisitExpr(E);
>> +  unsigned NumTemplateArgs = Record.readInt();
>> +  E->NestedNameSpec = Record.readNestedNameSpecifierLoc();
>> +  E->TemplateKWLoc = Record.readSourceLocation();
>> +  E->ConceptNameLoc = Record.readSourceLocation();
>> +  E->FoundDecl = ReadDeclAs<NamedDecl>();
>> +  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);
>> +  E->NamedConcept.setInt(Record.readInt() == 1);
>> +}
>> +
>>  void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
>>    VisitExpr(E);
>>    E->setLHS(Record.readSubExpr());
>> @@ -3490,6 +3508,12 @@ Stmt *ASTReader::ReadStmtFromStream(Modu
>>      case EXPR_DEPENDENT_COAWAIT:
>>        S = new (Context) DependentCoawaitExpr(Empty);
>>        break;
>> +
>> +    case EXPR_CONCEPT_SPECIALIZATION:
>> +      unsigned numTemplateArgs = Record[ASTStmtReader::NumExprFields];
>> +      S = ConceptSpecializationExpr::Create(Context, Empty,
>> numTemplateArgs);
>> +      break;
>> +
>>      }
>>
>>      // We hit a STMT_STOP, so we're done with this expression.
>>
>> Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
>> +++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Tue Oct 15 08:24:26 2019
>> @@ -388,6 +388,24 @@ void ASTStmtWriter::VisitDependentCoawai
>>    Code = serialization::EXPR_DEPENDENT_COAWAIT;
>>  }
>>
>> +void ASTStmtWriter::VisitConceptSpecializationExpr(
>> +        ConceptSpecializationExpr *E) {
>> +  VisitExpr(E);
>> +  ArrayRef<TemplateArgument> TemplateArgs = E->getTemplateArguments();
>> +  Record.push_back(TemplateArgs.size());
>> +  Record.AddNestedNameSpecifierLoc(E->getNestedNameSpecifierLoc());
>> +  Record.AddSourceLocation(E->getTemplateKWLoc());
>> +  Record.AddSourceLocation(E->getConceptNameLoc());
>> +  Record.AddDeclRef(E->getFoundDecl());
>> +  Record.AddDeclRef(E->getNamedConcept());
>> +  Record.AddASTTemplateArgumentListInfo(E->getTemplateArgsAsWritten());
>> +  for (const TemplateArgument &Arg : TemplateArgs)
>> +    Record.AddTemplateArgument(Arg);
>> +  Record.push_back(E->isSatisfied());
>> +  Code = serialization::EXPR_CONCEPT_SPECIALIZATION;
>> +}
>> +
>> +
>>  void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {
>>    VisitStmt(S);
>>    // NumCaptures
>>
>> Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
>> +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Tue Oct 15 08:24:26
>> 2019
>> @@ -1370,6 +1370,7 @@ void ExprEngine::Visit(const Stmt *S, Ex
>>      case Stmt::CUDAKernelCallExprClass:
>>      case Stmt::OpaqueValueExprClass:
>>      case Stmt::AsTypeExprClass:
>> +    case Stmt::ConceptSpecializationExprClass:
>>        // Fall through.
>>
>>      // Cases we intentionally don't evaluate, since they don't need
>>
>> Added: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp?rev=374903&view=auto
>>
>> ==============================================================================
>> --- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp (added)
>> +++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp Tue Oct 15
>> 08:24:26 2019
>> @@ -0,0 +1,149 @@
>> +// RUN:  %clang_cc1 -std=c++2a -verify -triple x86_64-linux-gnu %s
>> +
>> +template<typename T> concept C1 = true; // expected-note{{template is
>> declared here}}
>> +static_assert(C1<int>);
>> +static_assert(C1);
>> +// expected-error at -1{{use of concept 'C1' requires template arguments}}
>> +
>> +template<typename T> concept C2 = sizeof(T) == 4;
>> +static_assert(C2<int>);
>> +static_assert(!C2<long long int>);
>> +static_assert(C2<char[4]>);
>> +static_assert(!C2<char[5]>);
>> +
>> +template<typename T> concept C3 = sizeof(*T{}) == 4;
>> +static_assert(C3<int*>);
>> +static_assert(!C3<long long int>);
>> +
>> +struct A {
>> +  static constexpr int add(int a, int b) {
>> +    return a + b;
>> +  }
>> +};
>> +struct B {
>> +  static int add(int a, int b) { // expected-note{{declared here}}
>> +    return a + b;
>> +  }
>> +};
>> +template<typename U>
>> +concept C4 = U::add(1, 2) == 3;
>> +// expected-error at -1{{substitution into constraint expression resulted
>> in a non-constant expression}}
>> +// expected-note at -2{{non-constexpr function 'add' cannot be used in a
>> constant expression}}
>> +static_assert(C4<A>);
>> +static_assert(!C4<B>); // expected-note {{while checking the
>> satisfaction of concept 'C4<B>' requested here}}
>> +
>> +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, typename U>
>> +concept Same = is_same_v<T, U>;
>> +
>> +static_assert(Same<int, int>);
>> +static_assert(Same<int, decltype(1)>);
>> +static_assert(!Same<int, unsigned int>);
>> +static_assert(!Same<A, B>);
>> +static_assert(Same<A, A>);
>> +
>> +static_assert(Same<bool, decltype(C1<int>)>);
>> +static_assert(Same<bool, decltype(C2<int>)>);
>> +static_assert(Same<bool, decltype(C3<int*>)>);
>> +static_assert(Same<bool, decltype(C4<A>)>);
>> +
>> +template<typename T> concept C5 = T{}; // expected-error {{atomic
>> constraint must be of type 'bool' (found 'int')}}
>> +constexpr bool x = C5<int>; // expected-note {{while checking the
>> satisfaction of concept 'C5<int>' requested here}}
>> +
>> +template<int x>
>> +concept IsEven = (x % 2) == 0;
>> +
>> +static_assert(IsEven<20>);
>> +static_assert(!IsEven<11>);
>> +
>> +template<template<typename T> typename P>
>> +concept IsTypePredicate = is_same_v<decltype(P<bool>::value), const bool>
>> +                          && is_same_v<decltype(P<int>::value), const
>> bool>
>> +                          && is_same_v<decltype(P<long long>::value),
>> const bool>;
>> +
>> +template<typename T> struct T1 {};
>> +template<typename T> struct T2 { static constexpr bool value = sizeof(T)
>> == 2; };
>> +
>> +static_assert(IsTypePredicate<T2>);
>> +static_assert(!IsTypePredicate<T1>);
>> +
>> +namespace piecewise_substitution {
>> +  template <typename T>
>> +  concept True = true;
>> +
>> +  template <typename T>
>> +  concept A = True<T> || T::value;
>> +
>> +  template <typename T>
>> +  concept B = (True<T> || T::value);
>> +
>> +  template <typename T>
>> +  concept C = !True<T> && T::value || true;
>> +
>> +  template <typename T>
>> +  concept D = (!True<T> && T::value) || true;
>> +
>> +  template <typename T>
>> +  concept E = T::value || True<T>;
>> +
>> +  template <typename T>
>> +  concept F = (T::value || True<T>);
>> +
>> +  template <typename T>
>> +  concept G = T::value && !True<T> || true;
>> +
>> +  template <typename T>
>> +  concept H = (T::value && !True<T>) || true;
>> +
>> +  template <typename T>
>> +  concept I = T::value;
>> +
>> +  static_assert(A<int>);
>> +  static_assert(B<int>);
>> +  static_assert(C<int>);
>> +  static_assert(D<int>);
>> +  static_assert(E<int>);
>> +  static_assert(F<int>);
>> +  static_assert(G<int>);
>> +  static_assert(H<int>);
>> +  static_assert(!I<int>);
>> +}
>> +
>> +// Short ciruiting
>> +
>> +template<typename T> struct T3 { using type = typename T::type; };
>> +// expected-error at -1{{type 'char' cannot be used prior to '::' because
>> it has no members}}
>> +// expected-error at -2{{type 'short' cannot be used prior to '::' because
>> it has no members}}
>> +
>> +template<typename T>
>> +concept C6 = sizeof(T) == 1 && sizeof(typename T3<T>::type) == 1;
>> +// expected-note at -1{{while substituting template arguments into
>> constraint expression here}}
>> +// expected-note at -2{{in instantiation of template class 'T3<char>'
>> requested here}}
>> +
>> +template<typename T>
>> +concept C7 = sizeof(T) == 1 || sizeof(
>> +// expected-note at -1{{while substituting template arguments into
>> constraint expression here}}
>> +    typename
>> +      T3<T>
>> +// expected-note at -1{{in instantiation of template class 'T3<short>'
>> requested here}}
>> +        ::type) == 1;
>> +
>> +static_assert(!C6<short>);
>> +static_assert(!C6<char>); // expected-note{{while checking the
>> satisfaction of concept 'C6<char>' requested here}}
>> +static_assert(C7<char>);
>> +static_assert(!C7<short>); // expected-note{{while checking the
>> satisfaction of concept 'C7<short>' requested here}}
>> +
>> +// Make sure argument list is converted when instantiating a CSE.
>> +
>> +template<typename T, typename U = int>
>> +concept SameSize = sizeof(T) == sizeof(U);
>> +
>> +template<typename T>
>> +struct X { static constexpr bool a = SameSize<T>; };
>> +
>> +static_assert(X<unsigned>::a);
>>
>> Added:
>> cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp?rev=374903&view=auto
>>
>> ==============================================================================
>> ---
>> cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
>> (added)
>> +++
>> cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
>> Tue Oct 15 08:24:26 2019
>> @@ -0,0 +1,65 @@
>> +// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s
>> +
>> +namespace nodiag {
>> +
>> +template <typename T> requires bool(T())
>> +struct A;
>> +template <typename U> requires bool(U())
>> +struct A;
>> +
>> +} // end namespace nodiag
>> +
>> +namespace diag {
>> +
>> +template <typename T> requires true // expected-note{{previous template
>> declaration is here}}
>> +struct A;
>> +template <typename T> struct A; // expected-error{{associated
>> constraints differ in template redeclaration}}
>> +
>> +template <typename T> struct B; // expected-note{{previous template
>> declaration is here}}
>> +template <typename T> requires true // expected-error{{associated
>> constraints differ in template redeclaration}}
>> +struct B;
>> +
>> +template <typename T> requires true // expected-note{{previous template
>> declaration is here}}
>> +struct C;
>> +template <typename T> requires !0 // expected-error{{associated
>> constraints differ in template redeclaration}}
>> +struct C;
>> +
>> +} // end namespace diag
>> +
>> +namespace nodiag {
>> +
>> +struct AA {
>> +  template <typename T> requires someFunc(T())
>> +  struct A;
>> +};
>> +
>> +template <typename T> requires someFunc(T())
>> +struct AA::A { };
>> +
>> +struct AAF {
>> +  template <typename T> requires someFunc(T())
>> +  friend struct AA::A;
>> +};
>> +
>> +} // end namespace nodiag
>> +
>> +namespace diag {
>> +
>> +template <unsigned N>
>> +struct TA {
>> +  template <template <unsigned> class TT> requires TT<N>::happy //
>> expected-note 2{{previous template declaration is here}}
>> +  struct A;
>> +
>> +  struct AF;
>> +};
>> +
>> +template <unsigned N>
>> +template <template <unsigned> class TT> struct TA<N>::A { }; //
>> expected-error{{associated constraints differ in template redeclaration}}
>> +
>> +template <unsigned N>
>> +struct TA<N>::AF {
>> +  template <template <unsigned> class TT> requires TT<N + 0>::happy //
>> expected-error{{associated constraints differ in template redeclaration}}
>> +  friend struct TA::A;
>> +};
>> +
>> +} // end namespace diag
>>
>> Added: cfe/trunk/test/PCH/cxx2a-concept-specialization-expr.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx2a-concept-specialization-expr.cpp?rev=374903&view=auto
>>
>> ==============================================================================
>> --- cfe/trunk/test/PCH/cxx2a-concept-specialization-expr.cpp (added)
>> +++ cfe/trunk/test/PCH/cxx2a-concept-specialization-expr.cpp Tue Oct 15
>> 08:24:26 2019
>> @@ -0,0 +1,32 @@
>> +// RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t
>> +// RUN: %clang_cc1 -std=c++2a -include-pch %t -verify %s
>> +
>> +// expected-no-diagnostics
>> +
>> +#ifndef HEADER
>> +#define HEADER
>> +
>> +template<typename... T>
>> +concept C = true;
>> +
>> +namespace n {
>> +  template<typename... T>
>> +  concept C = true;
>> +}
>> +
>> +void f() {
>> +  (void)C<int>;
>> +  (void)C<int, void>;
>> +  (void)n::C<void>;
>> +}
>> +
>> +#else /*included pch*/
>> +
>> +int main() {
>> +  (void)C<int>;
>> +  (void)C<int, void>;
>> +  (void)n::C<void>;
>> +  f();
>> +}
>> +
>> +#endif // HEADER
>>
>> Modified: cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp (original)
>> +++ cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp Tue Oct 15
>> 08:24:26 2019
>> @@ -14,8 +14,6 @@ template<template<typename> concept T> c
>>  // expected-error at -2{{template template parameter requires 'class'
>> after the parameter list}}
>>  // expected-error at -3{{concept template parameter list must have at
>> least one parameter; explicit specialization of concepts is not allowed}}
>>
>> -template<typename T> concept C2 = 0.f; // expected-error {{constraint
>> expression must be of type 'bool' but is of type 'float'}}
>> -
>>  struct S1 {
>>    template<typename T> concept C1 = true; // expected-error {{concept
>> declarations may only appear in global or namespace scope}}
>>  };
>> @@ -26,15 +24,15 @@ extern "C++" {
>>
>>  template<typename A>
>>  template<typename B>
>> -concept C4 = true; // expected-error {{extraneous template parameter
>> list in concept definition}}
>> +concept C2 = true; // expected-error {{extraneous template parameter
>> list in concept definition}}
>>
>> -template<typename T> concept C5 = true; // expected-note {{previous}}
>> expected-note {{previous}}
>> -int C5; // expected-error {{redefinition}}
>> -struct C5 {}; // expected-error {{redefinition}}
>> -
>> -struct C6 {}; // expected-note{{previous definition is here}}
>> -template<typename T> concept C6 = true;
>> -// expected-error at -1{{redefinition of 'C6' as different kind of symbol}}
>> +template<typename T> concept C3 = true; // expected-note {{previous}}
>> expected-note {{previous}}
>> +int C3; // expected-error {{redefinition}}
>> +struct C3 {}; // expected-error {{redefinition}}
>> +
>> +struct C4 {}; // expected-note{{previous definition is here}}
>> +template<typename T> concept C4 = true;
>> +// expected-error at -1{{redefinition of 'C4' as different kind of symbol}}
>>
>>  // TODO: Add test to prevent explicit specialization, partial
>> specialization
>>  // and explicit instantiation of concepts.
>> @@ -43,31 +41,60 @@ template<typename T, T v>
>>  struct integral_constant { static constexpr T value = v; };
>>
>>  namespace N {
>> -  template<typename T> concept C7 = true;
>> +  template<typename T> concept C5 = true;
>>  }
>> -using N::C7;
>> +using N::C5;
>>
>> -template <bool word> concept C8 = integral_constant<bool, wor>::value;
>> +template <bool word> concept C6 = integral_constant<bool, wor>::value;
>>  // expected-error at -1{{use of undeclared identifier 'wor'; did you mean
>> 'word'?}}
>>  // expected-note at -2{{'word' declared here}}
>>
>> -template<typename T> concept bool C9 = true;
>> +template<typename T> concept bool C7 = true;
>>  // expected-warning at -1{{ISO C++2a does not permit the 'bool' keyword
>> after 'concept'}}
>>
>> -template<> concept C10 = false;
>> +template<> concept C8 = false;
>>  // expected-error at -1{{concept template parameter list must have at
>> least one parameter; explicit specialization of concepts is not allowed}}
>>
>> -template<> concept C9<int> = false;
>> +template<> concept C7<int> = false;
>>  // expected-error at -1{{name defined in concept definition must be an
>> identifier}}
>>
>> -template<typename T> concept N::C11 = false;
>> +template<typename T> concept N::C9 = false;
>>  // expected-error at -1{{name defined in concept definition must be an
>> identifier}}
>>
>>  class A { };
>>  // expected-note at -1{{'A' declared here}}
>>
>> -template<typename T> concept A::C12 = false;
>> +template<typename T> concept A::C10 = false;
>>  // expected-error at -1{{expected namespace name}}
>>
>>  template<typename T> concept operator int = false;
>>  // expected-error at -1{{name defined in concept definition must be an
>> identifier}}
>> +
>> +template<bool x> concept C11 = 2; // expected-error {{atomic constraint
>> must be of type 'bool' (found 'int')}}
>> +template<bool x> concept C12 = 2 && x; // expected-error {{atomic
>> constraint must be of type 'bool' (found 'int')}}
>> +template<bool x> concept C13 = x || 2 || x; // expected-error {{atomic
>> constraint must be of type 'bool' (found 'int')}}
>> +template<bool x> concept C14 = 8ull && x || x; // expected-error
>> {{atomic constraint must be of type 'bool' (found 'unsigned long long')}}
>> +template<typename T> concept C15 = sizeof(T); // expected-error {{atomic
>> constraint must be of type 'bool'}}
>> +template<typename T> concept C16 = true && (0 && 0); // expected-error
>> {{atomic constraint must be of type 'bool' (found 'int')}}
>> +// expected-warning at -1{{use of logical '&&' with constant operand}}
>> +// expected-note at -2{{use '&' for a bitwise operation}}
>> +// expected-note at -3{{remove constant to silence this warning}}
>> +template<typename T> concept C17 = T{};
>> +static_assert(!C17<bool>);
>> +template<typename T> concept C18 = (bool&&)true;
>> +static_assert(C18<int>);
>> +template<typename T> concept C19 = (const bool&)true;
>> +static_assert(C19<int>);
>> +template<typename T> concept C20 = (const bool)true;
>> +static_assert(C20<int>);
>> +template <bool c> concept C21 = integral_constant<bool, c>::value &&
>> true;
>> +static_assert(C21<true>);
>> +static_assert(!C21<false>);
>> +template <bool c> concept C22 = integral_constant<bool, c>::value;
>> +static_assert(C22<true>);
>> +static_assert(!C22<false>);
>> +
>> +template <bool word> concept C23 = integral_constant<bool, wor>::value;
>> +// expected-error at -1{{use of undeclared identifier 'wor'; did you mean
>> 'word'?}}
>> +// expected-note at -2{{'word' declared here}}
>> +
>>
>> Modified: cfe/trunk/tools/libclang/CXCursor.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXCursor.cpp?rev=374903&r1=374902&r2=374903&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/tools/libclang/CXCursor.cpp (original)
>> +++ cfe/trunk/tools/libclang/CXCursor.cpp Tue Oct 15 08:24:26 2019
>> @@ -256,6 +256,7 @@ CXCursor cxcursor::MakeCXCursor(const St
>>    case Stmt::BinaryConditionalOperatorClass:
>>    case Stmt::TypeTraitExprClass:
>>    case Stmt::CoawaitExprClass:
>> +  case Stmt::ConceptSpecializationExprClass:
>>    case Stmt::DependentCoawaitExprClass:
>>    case Stmt::CoyieldExprClass:
>>    case Stmt::CXXBindTemporaryExprClass:
>>
>>
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at lists.llvm.org
>> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20191015/636dadc8/attachment-0001.html>


More information about the cfe-commits mailing list