saar.raz updated this revision to Diff 137906.
saar.raz added a comment.

- Fixed incorrect checking of atomic constraint types.


Repository:
  rC Clang

https://reviews.llvm.org/D41217

Files:
  include/clang/AST/DeclTemplate.h
  include/clang/AST/ExprCXX.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/StmtNodes.td
  include/clang/Sema/Sema.h
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/Expr.cpp
  lib/AST/ExprCXX.cpp
  lib/AST/ExprClassification.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/Parse/ParseExpr.cpp
  lib/Parse/ParseTemplate.cpp
  lib/Sema/CMakeLists.txt
  lib/Sema/SemaConcept.cpp
  lib/Sema/SemaExceptionSpec.cpp
  lib/Sema/SemaExprCXX.cpp
  lib/Sema/SemaTemplate.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp
  test/Parser/cxx-concept-declaration.cpp
  tools/libclang/CXCursor.cpp

Index: tools/libclang/CXCursor.cpp
===================================================================
--- tools/libclang/CXCursor.cpp
+++ tools/libclang/CXCursor.cpp
@@ -231,6 +231,7 @@
   case Stmt::TypeTraitExprClass:
   case Stmt::CoroutineBodyStmtClass:
   case Stmt::CoawaitExprClass:
+  case Stmt::ConceptSpecializationExprClass:
   case Stmt::DependentCoawaitExprClass:
   case Stmt::CoreturnStmtClass:
   case Stmt::CoyieldExprClass:
Index: test/Parser/cxx-concept-declaration.cpp
===================================================================
--- test/Parser/cxx-concept-declaration.cpp
+++ test/Parser/cxx-concept-declaration.cpp
@@ -9,8 +9,6 @@
 
 template<concept T> concept D1 = true; // expected-error {{expected template parameter}}
 
-template<typename T> concept C2 = 0.f; // expected-error {{constraint expression must be 'bool'}}
-
 struct S1 {
   template<typename T> concept C1 = true; // expected-error {{concept declarations may only appear in global or namespace scope}}
 };
@@ -29,3 +27,22 @@
 
 // TODO: Add test to prevent explicit specialization, partial specialization
 // and explicit instantiation of concepts.
+
+template<bool x> concept C7 = 2; // expected-error {{atomic constraint '2' must be of type 'bool' (found 'int')}}
+template<bool x> concept C8 = 2 && x; // expected-error {{atomic constraint '2' must be of type 'bool' (found 'int')}}
+template<bool x> concept C9 = x || 2 || x; // expected-error {{atomic constraint '2' must be of type 'bool' (found 'int')}}
+template<bool x> concept C10 = 8ull && x || x; // expected-error {{atomic constraint '8ULL' must be of type 'bool' (found 'unsigned long long')}}
+template<typename T> concept C11 = sizeof(T); // expected-error {{atomic constraint 'sizeof(T)' must be of type 'bool' (found 'unsigned long')}}
+template<typename T> concept C12 = T{};
+template<typename T> concept C13 = (bool&&)true;
+template<typename T> concept C14 = (const bool&)true;
+template<typename T> concept C15 = (const bool)true;
+
+template<typename T, T v>
+struct integral_constant { static constexpr T value = v; };
+
+template <bool c> concept C16 = integral_constant<bool, c>::value && true;
+template <bool c> concept C17 = integral_constant<bool, c>::value;
+
+bool a = C16<true>;
+bool b = C17<true>;
Index: test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp
===================================================================
--- test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp
+++ test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp
@@ -1,5 +1,69 @@
 // RUN:  %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
-// expected-no-diagnostics
 
-template<typename T> concept C = true;
-static_assert(C<int>);
+template<typename T> concept C1 = true;
+static_assert(C1<int>);
+
+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) {
+        return a + b;
+    }
+};
+template<typename U>
+concept C4 = U::add(1, 2) == 3;
+static_assert(C4<A>);
+static_assert(!C4<B>); // expected-error {{concept specialization 'C4<B>' resulted in a non-constant expression 'B::add(1, 2) == 3'}}
+
+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 'int{}' must be of type 'bool' (found 'int')}}
+constexpr bool x = C5<int>; // expected-note {{in concept specialization 'C5<int>'}}
+
+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>);
\ No newline at end of file
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1018,6 +1018,7 @@
     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
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -344,6 +344,23 @@
   Code = serialization::EXPR_DEPENDENT_COAWAIT;
 }
 
+void ASTStmtWriter::VisitConceptSpecializationExpr(
+        ConceptSpecializationExpr *E) {
+  VisitExpr(E);
+  Record.AddDeclRef(E->getSpecializedConcept());
+  Record.AddSourceLocation(E->getConceptNameLoc());
+  const TemplateArgumentListInfo *TALI = E->getTemplateArgumentListInfo();
+  Record.push_back(TALI->size());
+  Record.AddSourceLocation(TALI->getLAngleLoc());
+  Record.AddSourceLocation(TALI->getRAngleLoc());
+  for (unsigned i = 0; i < TALI->size(); ++i) {
+    Record.AddTemplateArgumentLoc(TALI->getArgumentArray()[i]);
+  }
+  Record.push_back(E->isSatisfied());
+  Code = serialization::EXPR_CONCEPT_SPECIALIZATION;
+}
+
+
 void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {
   VisitStmt(S);
   // NumCaptures
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -610,6 +610,22 @@
   E->setRParenLoc(ReadSourceLocation());
 }
 
+void ASTStmtReader::VisitConceptSpecializationExpr(
+        ConceptSpecializationExpr *E) {
+  VisitExpr(E);
+  E->setSpecializedConcept(ReadDeclAs<ConceptDecl>());
+  E->setConceptNameLoc(Record.readSourceLocation());
+
+  TemplateArgumentListInfo ArgInfo;
+  unsigned NumTemplateArgs = Record.readInt();
+  ArgInfo.setLAngleLoc(Record.readSourceLocation());
+  ArgInfo.setRAngleLoc(Record.readSourceLocation());
+  for (unsigned i = 0; i != NumTemplateArgs; ++i)
+    ArgInfo.addArgument(Record.readTemplateArgumentLoc());
+  E->setTemplateArguments(/*Sema=*/nullptr, &ArgInfo);
+  E->setSatisfied(Record.readInt() == 1);
+}
+
 void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
   VisitExpr(E);
   E->setLHS(Record.readSubExpr());
@@ -4033,6 +4049,9 @@
       S = new (Context) DependentCoawaitExpr(Empty);
       break;
 
+    case EXPR_CONCEPT_SPECIALIZATION:
+      S = new (Context) ConceptSpecializationExpr(Context, Empty);
+      break;
     }
 
     // We hit a STMT_STOP, so we're done with this expression.
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -2940,7 +2940,22 @@
                                   RParenLoc, Length, PartialArgs);
   }
 
-  /// \brief Build a new Objective-C boxed expression.
+  /// \brief Build a new concept specialization expression.
+  ///
+  /// By default, performs semantic analysis to build the new expression.
+  /// Subclasses may override this routine to provide different behavior.
+  ExprResult RebuildConceptSpecializationExpr(SourceLocation ConceptNameLoc,
+                                              ConceptDecl *CTD,
+                                              TemplateArgumentListInfo *TALI) {
+    ExprResult Result
+            = getSema().CreateConceptSpecializationExpr(ConceptNameLoc, CTD,
+                                                        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.
@@ -10616,6 +10631,23 @@
                                        E->getLocEnd());
 }
 
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformConceptSpecializationExpr(
+                                                 ConceptSpecializationExpr *E) {
+  const TemplateArgumentListInfo *Old = E->getTemplateArgumentListInfo();
+  TemplateArgumentListInfo TransArgs(Old->getLAngleLoc(), Old->getRAngleLoc());
+  if (getDerived().TransformTemplateArguments(Old->getArgumentArray(),
+          Old->size(), TransArgs)) {
+    return ExprError();
+  }
+
+  return getDerived().RebuildConceptSpecializationExpr(E->getConceptNameLoc(),
+                                                     E->getSpecializedConcept(),
+                                                       &TransArgs);
+}
+
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3893,10 +3893,17 @@
                              ConceptDecl *Template,
                              SourceLocation TemplateLoc,
                              const TemplateArgumentListInfo *TemplateArgs) {
-  // TODO: Do more stuff here, caller expects constraint
-  // expression to be returned. Works for non-dependent bool
-  // constraint expressions right now.
-  return Template->getConstraintExpr();
+  assert(Template && "A concept template id without template?");
+
+  // Check that the template argument list is well-formed for this template.
+  SmallVector<TemplateArgument, 4> Converted;
+  if (CheckTemplateArgumentList(Template, TemplateLoc,
+        const_cast<TemplateArgumentListInfo &>(*TemplateArgs), false,
+          Converted, /*UpdateArgsWithConversions=*/false))
+    return ExprError();
+
+  return CreateConceptSpecializationExpr(NameInfo.getLoc(), Template,
+                                         TemplateArgs);
 }
 
 ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
@@ -7710,19 +7717,6 @@
   if (!NewDecl)
     return nullptr;
 
-  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.
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -7678,3 +7678,11 @@
 
   return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo);
 }
+
+
+ExprResult Sema::CreateConceptSpecializationExpr(SourceLocation ConceptNameLoc,
+                                                 ConceptDecl *CTD,
+                                         const TemplateArgumentListInfo *TALI) {
+  return new (Context) ConceptSpecializationExpr(Context, *this, ConceptNameLoc,
+                                                 CTD, TALI);
+}
\ No newline at end of file
Index: lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- lib/Sema/SemaExceptionSpec.cpp
+++ lib/Sema/SemaExceptionSpec.cpp
@@ -1271,6 +1271,7 @@
   case Expr::PredefinedExprClass:
   case Expr::SizeOfPackExprClass:
   case Expr::StringLiteralClass:
+  case Expr::ConceptSpecializationExprClass:
     // These expressions can never throw.
     return CT_Cannot;
 
Index: lib/Sema/SemaConcept.cpp
===================================================================
--- /dev/null
+++ lib/Sema/SemaConcept.cpp
@@ -0,0 +1,44 @@
+//===-- 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/SemaInternal.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.
+
+  if (BinaryOperator* BinOp = dyn_cast<BinaryOperator>(ConstraintExpression)) {
+    if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr) {
+      return CheckConstraintExpression(BinOp->getLHS())
+        && CheckConstraintExpression(BinOp->getRHS());
+    }
+  }
+  // An atomic constraint!
+  if (!ConstraintExpression->isTypeDependent()) {
+    if (!Context.hasSameType(ConstraintExpression->getType()
+                                .getNonReferenceType().getUnqualifiedType(),
+                             Context.BoolTy)) {
+      Diag(ConstraintExpression->getExprLoc(),
+           diag::err_non_bool_atomic_constraint)
+              << ConstraintExpression << ConstraintExpression->getType();
+      return false;
+    } else if (ImplicitCastExpr *E =
+                             dyn_cast<ImplicitCastExpr>(ConstraintExpression)) {
+      // This will catch expressions such as '2 && true'
+      return CheckConstraintExpression(E->getSubExpr());
+    }
+  }
+  return true;
+}
\ No newline at end of file
Index: lib/Sema/CMakeLists.txt
===================================================================
--- lib/Sema/CMakeLists.txt
+++ lib/Sema/CMakeLists.txt
@@ -25,6 +25,7 @@
   SemaCast.cpp
   SemaChecking.cpp
   SemaCodeComplete.cpp
+  SemaConcept.cpp
   SemaConsumer.cpp
   SemaCoroutine.cpp
   SemaCUDA.cpp
Index: lib/Parse/ParseTemplate.cpp
===================================================================
--- lib/Parse/ParseTemplate.cpp
+++ lib/Parse/ParseTemplate.cpp
@@ -372,8 +372,7 @@
 
   ExprResult ConstraintExprResult = ParseConstraintExpression();
   if (ConstraintExprResult.isInvalid()) {
-    Diag(Tok.getLocation(), diag::err_expected_expression)
-      << "constraint-expression";
+    // ParseConstraintExpression will have given a sufficient diagnostic.
     return nullptr;
   }
 
Index: lib/Parse/ParseExpr.cpp
===================================================================
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -216,18 +216,14 @@
 /// \brief 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
   ExprResult LHS(ParseCastExpression(/*isUnaryExpression=*/false));
   ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr));
-
+  if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get()))
+    return ExprError();
   return Res;
 }
 
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp
+++ lib/CodeGen/CGExprScalar.cpp
@@ -602,6 +602,10 @@
     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());
   }
Index: lib/AST/StmtProfile.cpp
===================================================================
--- lib/AST/StmtProfile.cpp
+++ lib/AST/StmtProfile.cpp
@@ -1233,6 +1233,14 @@
   ID.AddInteger(S->getOp());
 }
 
+void StmtProfiler::VisitConceptSpecializationExpr(
+                                           const ConceptSpecializationExpr *S) {
+  VisitExpr(S);
+  VisitDecl(S->getSpecializedConcept());
+  VisitTemplateArguments(S->getTemplateArgumentListInfo()->getArgumentArray(),
+                         S->getTemplateArgumentListInfo()->size());
+}
+
 static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S,
                                           UnaryOperatorKind &UnaryOp,
                                           BinaryOperatorKind &BinaryOp) {
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -2549,6 +2549,12 @@
   OS << ")";
 }
 
+void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
+  OS << E->getSpecializedConcept()->getName();
+  printTemplateArgumentList(OS, E->getTemplateArgumentListInfo()->arguments(),
+                            Policy);
+}
+
 // C++ Coroutines TS
 
 void StmtPrinter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -3464,6 +3464,7 @@
   case Expr::ConvertVectorExprClass:
   case Expr::StmtExprClass:
   case Expr::TypeTraitExprClass:
+  case Expr::ConceptSpecializationExprClass:
   case Expr::ArrayTypeTraitExprClass:
   case Expr::ExpressionTraitExprClass:
   case Expr::VAArgExprClass:
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -7074,6 +7074,7 @@
   bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);
   bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
 
+  bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);
   // FIXME: Missing: array subscript of vector, member of vector
 };
 } // end anonymous namespace
@@ -9079,6 +9080,15 @@
   return Success(E->getValue(), E);
 }
 
+bool IntExprEvaluator::VisitConceptSpecializationExpr(
+       const ConceptSpecializationExpr *E) {
+  if (E->isValueDependent()) {
+    return Error(E);
+  }
+  return Success(E->isSatisfied(), E);
+}
+
+
 //===----------------------------------------------------------------------===//
 // Float Evaluation
 //===----------------------------------------------------------------------===//
@@ -10368,6 +10378,7 @@
   case Expr::CXXBoolLiteralExprClass:
   case Expr::CXXScalarValueInitExprClass:
   case Expr::TypeTraitExprClass:
+  case Expr::ConceptSpecializationExprClass:
   case Expr::ArrayTypeTraitExprClass:
   case Expr::ExpressionTraitExprClass:
   case Expr::CXXNoexceptExprClass:
Index: lib/AST/ExprClassification.cpp
===================================================================
--- lib/AST/ExprClassification.cpp
+++ lib/AST/ExprClassification.cpp
@@ -190,6 +190,7 @@
   case Expr::ArrayInitIndexExprClass:
   case Expr::NoInitExprClass:
   case Expr::DesignatedInitUpdateExprClass:
+  case Expr::ConceptSpecializationExprClass:
     return Cl::CL_PRValue;
 
     // Next come the complicated cases.
Index: lib/AST/ExprCXX.cpp
===================================================================
--- lib/AST/ExprCXX.cpp
+++ lib/AST/ExprCXX.cpp
@@ -29,6 +29,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"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -1433,3 +1436,98 @@
 }
 
 void ArrayTypeTraitExpr::anchor() {}
+
+ConceptSpecializationExpr::ConceptSpecializationExpr(ASTContext &C, Sema &S,
+                                                  SourceLocation ConceptNameLoc,
+                                                     ConceptDecl *CD,
+                                         const TemplateArgumentListInfo *TALI)
+  : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary,
+         /*TypeDependent=*/false,
+         // All the flags below are set in setTemplateArguments.
+         /*ValueDependent=*/false, /*InstantiationDependent=*/false,
+         /*ContainsUnexpandedParameterPacks=*/false), SpecializedConcept(CD),
+    ConceptNameLoc(ConceptNameLoc) {
+  setTemplateArguments(&S, TALI);
+}
+
+ConceptSpecializationExpr::ConceptSpecializationExpr(ASTContext &C,
+                                                     EmptyShell Empty)
+  : Expr(ConceptSpecializationExprClass, Empty) { }
+
+bool ConceptSpecializationExpr::evaluate(Sema &S)
+{
+  llvm::SmallVector<TemplateArgument, 4> Converted;
+  if (S.CheckTemplateArgumentList(SpecializedConcept,
+                                  SpecializedConcept->getLocStart(),
+                                  TemplateArgInfo,
+                                  /*PartialTemplateArgs=*/false, Converted,
+                                  /*UpdateArgsWithConversion=*/false)) {
+    // We converted these arguments back in CheckConceptTemplateId, this should
+    // work.
+    return true;
+  }
+  EnterExpressionEvaluationContext ConstantEvaluated(
+          S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+
+
+  MultiLevelTemplateArgumentList MLTAL;
+  MLTAL.addOuterTemplateArguments(Converted);
+
+  ExprResult E;
+  {
+    // We do not want error diagnostics escaping here.
+    Sema::SFINAETrap Trap(S);
+    E = S.SubstExpr(SpecializedConcept->getConstraintExpr(), 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 true;
+    }
+  }
+
+  if (!S.CheckConstraintExpression(E.get())) {
+    S.Diag(getLocStart(), diag::note_in_concept_specialization) << this;
+    return true;
+  }
+
+  bool Satisfied = false;
+  if (!E.get()->EvaluateAsBooleanCondition(Satisfied, S.Context)) {
+      // C++2a [temp.constr.atomic]p1
+      //   ...E shall be a constant expression of type bool.
+    S.Diag(getLocStart(), diag::err_concept_non_constant_constraint_expression)
+      << this << E.get();
+    return true;
+  }
+  IsSatisfied = Satisfied;
+  return false;
+}
+
+bool ConceptSpecializationExpr::setTemplateArguments(Sema *S,
+                                          const TemplateArgumentListInfo *TALI){
+  bool IsDependent = false;
+  bool ContainsUnexpandedParameterPack = false;
+  TemplateArgInfo = *TALI;
+  for (const TemplateArgumentLoc& LocInfo : TALI->arguments()) {
+    if (LocInfo.getArgument().isInstantiationDependent()) {
+      IsDependent = true;
+      if (ContainsUnexpandedParameterPack) {
+        break;
+      }
+    }
+    if (LocInfo.getArgument().containsUnexpandedParameterPack()) {
+      ContainsUnexpandedParameterPack = true;
+      if (IsDependent) {
+        break;
+      }
+    }
+  }
+  setValueDependent(IsDependent);
+  setInstantiationDependent(IsDependent);
+  setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack);
+  if (!IsDependent && S) {
+    return evaluate(*S);
+  }
+  return false;
+}
\ No newline at end of file
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -2998,6 +2998,7 @@
   case ObjCAvailabilityCheckExprClass:
   case CXXUuidofExprClass:
   case OpaqueValueExprClass:
+  case ConceptSpecializationExprClass:
     // These never have a side-effect.
     return false;
 
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -1789,6 +1789,7 @@
       EXPR_FUNCTION_PARM_PACK,    // FunctionParmPackExpr
       EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr
       EXPR_CXX_FOLD,              // CXXFoldExpr
+      EXPR_CONCEPT_SPECIALIZATION,// ConceptSpecializationExpr
 
       // CUDA
       EXPR_CUDA_KERNEL_CALL,       // CUDAKernelCallExpr      
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -5572,7 +5572,15 @@
                                            CXXConversionDecl *Conv,
                                            Expr *Src);
 
-  // ParseObjCStringLiteral - Parse Objective-C string literals.
+  ExprResult CreateConceptSpecializationExpr(SourceLocation ConceptNameLoc,
+                                             ConceptDecl *CTD,
+                                       const TemplateArgumentListInfo *TALI);
+
+  /// Check whether the given expression is a valid constraint expression.
+  /// A diagnostic is emmited if it is not, and false is returned.
+  bool CheckConstraintExpression(Expr *CE);
+
+    // ParseObjCStringLiteral - Parse Objective-C string literals.
   ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
                                     ArrayRef<Expr *> Strings);
 
Index: include/clang/Basic/StmtNodes.td
===================================================================
--- include/clang/Basic/StmtNodes.td
+++ include/clang/Basic/StmtNodes.td
@@ -153,6 +153,9 @@
 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>;
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2394,14 +2394,18 @@
 def err_concept_specialized : Error<
   "%select{function|variable}0 concept cannot be "
   "%select{explicitly instantiated|explicitly specialized|partially specialized}1">;
-def err_concept_initialized_with_non_bool_type : Error<
-  "constraint expression must be 'bool' but found %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_extra_headers : Error<
   "extraneous template parameter list in concept definition">;
 def err_concept_no_associated_constraints : Error<
   "concept may not have associated constraints">;
+def err_concept_non_constant_constraint_expression : Error<
+  "concept specialization '%0' resulted in a non-constant expression '%1'">;
+def err_non_bool_atomic_constraint : Error<
+  "atomic constraint '%0' must be of type 'bool' (found %1)">;
+def note_in_concept_specialization : Note<
+  "in concept specialization '%0'">;
 
 def err_template_different_associated_constraints : Error<
   "associated constraints differ in template redeclaration">;
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -2585,6 +2585,12 @@
   }
 })
 
+DEF_TRAVERSE_STMT(ConceptSpecializationExpr, {
+  TRY_TO(TraverseTemplateArgumentLocsHelper(
+          S->getTemplateArgumentListInfo()->getArgumentArray(),
+          S->getTemplateArgumentListInfo()->size()));
+})
+
 // These literals (all of them) do not need any action.
 DEF_TRAVERSE_STMT(IntegerLiteral, {})
 DEF_TRAVERSE_STMT(CharacterLiteral, {})
Index: include/clang/AST/ExprCXX.h
===================================================================
--- include/clang/AST/ExprCXX.h
+++ include/clang/AST/ExprCXX.h
@@ -57,6 +57,8 @@
 class LambdaCapture;
 class NonTypeTemplateParmDecl;
 class TemplateParameterList;
+class ConceptDecl;
+class Sema;
 
 //===--------------------------------------------------------------------===//
 // C++ Expressions.
@@ -4407,6 +4409,96 @@
   }
 };
 
+/// \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 concepts results in a prvalue of type bool.
+class ConceptSpecializationExpr final : public Expr {
+protected:
+  /// \brief The concept specialization this represents.
+  ConceptDecl *SpecializedConcept;
+
+  /// \brief The template argument list used to specialize the concept.
+  TemplateArgumentList *TemplateArgs;
+  TemplateArgumentListInfo TemplateArgInfo;
+
+  /// \brief The location of the concept name in the expression.
+  SourceLocation ConceptNameLoc;
+
+  /// \brief 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 is to be
+  /// ignored.
+  bool IsSatisfied : 1;
+
+  /// \brief Evaluates this concept specialization to determine whether or not
+  /// the concept is satisfied. Returns true if an error occured and the concept
+  /// could not be checked for satisfaction.
+  bool evaluate(Sema &S);
+
+public:
+  ConceptSpecializationExpr(ASTContext &C, Sema &S,
+                            SourceLocation ConceptNameLoc, ConceptDecl *CD,
+                            const TemplateArgumentListInfo *TALI);
+
+  ConceptSpecializationExpr(ASTContext &C, EmptyShell Empty);
+
+  ConceptDecl *getSpecializedConcept() {
+    return SpecializedConcept;
+  }
+  const ConceptDecl *getSpecializedConcept() const {
+    return SpecializedConcept;
+  }
+  void setSpecializedConcept(ConceptDecl *C) {
+    SpecializedConcept = C;
+  }
+
+  const TemplateArgumentList *getTemplateArguments() const {
+    return TemplateArgs;
+  }
+  const TemplateArgumentListInfo *getTemplateArgumentListInfo() const {
+    return &TemplateArgInfo;
+  }
+
+  /// \brief Set new template arguments for this concept specialization. Returns
+  /// true if an error occured (the template arguments do not match the concept,
+  /// probably)
+  bool setTemplateArguments(Sema *S, const TemplateArgumentListInfo *TALI);
+
+  /// \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 IsSatisfied;
+  }
+
+  void setSatisfied(bool Satisfied) {
+    IsSatisfied = Satisfied;
+  }
+
+  SourceLocation getConceptNameLoc() const { return ConceptNameLoc; }
+  void setConceptNameLoc(SourceLocation Loc) {
+    ConceptNameLoc = Loc;
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == ConceptSpecializationExprClass;
+  }
+
+  SourceLocation getLocStart() const LLVM_READONLY { return ConceptNameLoc; }
+  SourceLocation getLocEnd() const LLVM_READONLY {
+    return TemplateArgInfo.getRAngleLoc();
+  }
+
+  // Iterators
+  child_range children() {
+    return child_range(child_iterator(), child_iterator());
+  }
+};
+
 } // namespace clang
 
 #endif // LLVM_CLANG_AST_EXPRCXX_H
Index: include/clang/AST/DeclTemplate.h
===================================================================
--- include/clang/AST/DeclTemplate.h
+++ include/clang/AST/DeclTemplate.h
@@ -3058,9 +3058,9 @@
     ConstraintExpr = CE;
   }
 
-  // TODO: Should do source range properly.
+
   SourceRange getSourceRange() const override LLVM_READONLY {
-    return SourceRange(getLocation(), getLocation());
+    return SourceRange(getLocation(), getConstraintExpr()->getLocEnd());
   }
 
   // Implement isa/cast/dyncast/etc.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to