saar.raz created this revision.
saar.raz added reviewers: nwilson, hubert.reinterpretcast, changyu, rsmith, 
faisalv, Quuxplusone.
Herald added a subscriber: cfe-commits.

Depends on https://reviews.llvm.org/D41910.


Repository:
  rC Clang

https://reviews.llvm.org/D43357

Files:
  include/clang/AST/Decl.h
  include/clang/AST/DeclCXX.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/Basic/DiagnosticParseKinds.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/DeclSpec.h
  include/clang/Sema/Overload.h
  include/clang/Sema/Sema.h
  lib/AST/ASTDumper.cpp
  lib/AST/ASTImporter.cpp
  lib/AST/Decl.cpp
  lib/AST/DeclCXX.cpp
  lib/AST/DeclPrinter.cpp
  lib/AST/DeclTemplate.cpp
  lib/AST/ODRHash.cpp
  lib/Parse/ParseDecl.cpp
  lib/Parse/ParseTentative.cpp
  lib/Sema/DeclSpec.cpp
  lib/Sema/SemaCast.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclAttr.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaOverload.cpp
  lib/Sema/SemaTemplateDeduction.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  lib/Sema/SemaTemplateVariadic.cpp
  lib/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriterDecl.cpp
  test/CXX/concepts-ts/class.derived/class.virtual/p6.cpp
  test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p1.cpp
  test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p2.cpp
  test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p5.cpp
  test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p6.cpp
  test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p7.cpp
  test/CXX/concepts-ts/dcl.dcl/lit.cfg.py
  test/CXX/concepts-ts/dcl/dcl.dcl/dcl.spec/dcl.spec.concept/p1.cpp
  test/CXX/concepts-ts/dcl/dcl.dcl/dcl.spec/dcl.spec.concept/p2.cpp
  test/CXX/concepts-ts/dcl/dcl.dcl/dcl.spec/dcl.spec.concept/p5.cpp
  test/CXX/concepts-ts/dcl/dcl.dcl/dcl.spec/dcl.spec.concept/p6.cpp
  test/CXX/concepts-ts/dcl/dcl.dcl/dcl.spec/dcl.spec.concept/p7.cpp
  test/CXX/concepts-ts/dcl/dcl.dcl/lit.cfg.py
  test/CXX/concepts-ts/dcl/dcl.decl/p3.cpp
  test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/mixed-constraints.cpp
  test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p4.cpp
  test/CXX/concepts-ts/over/over.match/over.match.best/p1.cpp
  test/CXX/concepts-ts/over/over.over/p4.cpp

Index: test/CXX/concepts-ts/over/over.over/p4.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/over/over.over/p4.cpp
@@ -0,0 +1,56 @@
+// RUN:  %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+
+
+template<typename T, typename U>
+constexpr static bool is_same_v = false;
+
+template<typename T>
+constexpr static bool is_same_v<T, T> = true;
+
+template<typename T>
+concept AtLeast2 = sizeof(T) >= 2;
+
+template<typename T>
+concept AtMost8 = sizeof(T) <= 8;
+
+int foo() requires AtLeast2<long> && AtMost8<long> {
+  return 0;
+}
+
+double foo() requires AtLeast2<char> {
+  return 0.0;
+}
+
+char bar() requires AtLeast2<char> { // expected-note {{possible target for call}}
+  return 1.0;
+}
+
+short bar() requires AtLeast2<long> && AtMost8<long> { // expected-note {{possible target for call}} expected-note {{candidate function}}
+  return 0.0;
+}
+
+int bar() requires AtMost8<long> && AtLeast2<long> { // expected-note {{possible target for call}} expected-note {{candidate function}}
+  return 0.0;
+}
+
+char baz() requires AtLeast2<char> {
+  return 1.0;
+}
+
+short baz() requires AtLeast2<long> && AtMost8<long> {
+  return 0.0;
+}
+
+int baz() requires AtMost8<long> && AtLeast2<long> {
+  return 0.0;
+}
+
+long baz() requires AtMost8<long> && AtLeast2<long> && AtLeast2<short> {
+  return 3.0;
+}
+
+void a() {
+  static_assert(is_same_v<decltype(&foo), int(*)()>);
+  static_assert(is_same_v<decltype(&bar), long(*)()>); // expected-error {{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}} expected-error{{call to 'bar' is ambiguous}}
+  static_assert(is_same_v<decltype(&baz), long(*)()>);
+}
\ No newline at end of file
Index: test/CXX/concepts-ts/over/over.match/over.match.best/p1.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/over/over.match/over.match.best/p1.cpp
@@ -0,0 +1,65 @@
+// RUN:  %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+
+
+template<typename T, typename U>
+constexpr static bool is_same_v = false;
+
+template<typename T>
+constexpr static bool is_same_v<T, T> = true;
+
+namespace templates
+{
+  template<typename T>
+  concept AtLeast1 = sizeof(T) >= 1;
+
+  template<typename T>
+  int foo(T t) requires sizeof(T) == 4 { // expected-note {{candidate function}}
+    return 0;
+  }
+
+  template<typename T>
+  char foo(T t) requires AtLeast1<T> { // expected-note {{candidate function}}
+    return 'a';
+  }
+
+  template<typename T>
+  double foo(T t) requires AtLeast1<T> && sizeof(T) <= 2 {
+    return 'a';
+  }
+
+  void bar() {
+    static_assert(is_same_v<decltype(foo(10)), int>); // expected-error {{call to 'foo' is ambiguous}}
+    static_assert(is_same_v<decltype(foo(short(10))), double>);
+  }
+}
+
+namespace non_template
+{
+  template<typename T>
+  concept AtLeast2 = sizeof(T) >= 2;
+
+  template<typename T>
+  concept AtMost8 = sizeof(T) <= 8;
+
+  int foo() requires AtLeast2<long> && AtMost8<long> {
+    return 0;
+  }
+
+  double foo() requires AtLeast2<long> {
+    return 0.0;
+  }
+
+  double baz() requires AtLeast2<long> && AtMost8<long> { // expected-note {{candidate function}}
+    return 0.0;
+  }
+
+  int baz() requires AtMost8<long> && AtLeast2<long> { // expected-note {{candidate function}}
+    return 0.0;
+  }
+
+  void bar() {
+    static_assert(is_same_v<decltype(foo()), int>);
+    static_assert(is_same_v<decltype(baz()), int>); // expected-error {{call to 'baz' is ambiguous}}
+  }
+}
+
Index: test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p4.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p4.cpp
@@ -0,0 +1,56 @@
+// RUN:  %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+
+namespace functions
+{
+  void foo(int) requires false {} // expected-note 3{{because 'false' evaluated to false}}
+  void bar(int) requires true {}
+
+  void a(int);
+  void a(double);
+
+  void baz() {
+    foo(1); // expected-error{{invalid reference to function 'foo' - constraints not satisfied}}
+    bar(1);
+    void (*p1)(int) = foo; // expected-error{{invalid reference to function 'foo' - constraints not satisfied}}
+    void (*p3)(int) = bar;
+    decltype(foo)* a1 = nullptr; // expected-error{{invalid reference to function 'foo' - constraints not satisfied}}
+    decltype(bar)* a2 = nullptr;
+  }
+}
+
+namespace methods
+{
+  template<typename T>
+  struct A {
+    static void foo(int) requires sizeof(T) == 1 {} // expected-note 3{{because 'sizeof(char [2]) == 1' (2 == 1) evaluated to false}}
+    static void bar(int) requires sizeof(T) == 2 {} // expected-note 3{{because 'sizeof(char) == 2' (1 == 2) evaluated to false}}
+  };
+
+  void baz() {
+    A<char>::foo(1);
+    A<char>::bar(1); // expected-error{{invalid reference to function 'bar' - constraints not satisfied}}
+    A<char[2]>::foo(1); // expected-error{{invalid reference to function 'foo' - constraints not satisfied}}
+    A<char[2]>::bar(1);
+    void (*p1)(int) = A<char>::foo;
+    void (*p2)(int) = A<char>::bar; // expected-error{{invalid reference to function 'bar' - constraints not satisfied}}
+    void (*p3)(int) = A<char[2]>::foo; // expected-error{{invalid reference to function 'foo' - constraints not satisfied}}
+    void (*p4)(int) = A<char[2]>::bar;
+    decltype(A<char>::foo)* a1 = nullptr;
+    decltype(A<char>::bar)* a2 = nullptr; // expected-error{{invalid reference to function 'bar' - constraints not satisfied}}
+    decltype(A<char[2]>::foo)* a3 = nullptr; // expected-error{{invalid reference to function 'foo' - constraints not satisfied}}
+    decltype(A<char[2]>::bar)* a4 = nullptr;
+  }
+}
+
+namespace operators
+{
+  template<typename T>
+  struct A {
+    A<T> operator-(A<T> b) requires sizeof(T) == 1 { return b; } // expected-note{{because 'sizeof(int) == 1' (4 == 1) evaluated to false}}
+  };
+
+  void baz() {
+    auto* x = &A<int>::operator-; // expected-error{{invalid reference to function 'operator-' - constraints not satisfied}}
+    auto y = &A<char>::operator-;
+  }
+}
\ No newline at end of file
Index: test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/mixed-constraints.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/mixed-constraints.cpp
@@ -0,0 +1,12 @@
+// RUN:  %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+
+template<typename T> requires sizeof(T) >= 4 && sizeof(T) <= 10 // expected-note{{because 'sizeof(char [20]) <= 10' (20 <= 10) evaluated to false}} expected-note{{because 'sizeof(char) >= 4' (1 >= 4) evaluated to false}}
+void foo() requires sizeof(T) <= 8 {} // expected-note{{candidate template ignored: constraints not satisfied [with T = char]}} expected-note{{candidate template ignored: constraints not satisfied [with T = char [9]]}} expected-note{{candidate template ignored: constraints not satisfied [with T = char [20]]}} expected-note{{and 'sizeof(char [20]) <= 8' (20 <= 8) evaluated to false}} expected-note{{because 'sizeof(char [9]) <= 8' (9 <= 8) evaluated to false}}
+
+void bar() {
+  foo<char>(); // expected-error{{no matching function for call to 'foo'}}
+  foo<int>();
+  foo<unsigned long long int>();
+  foo<char[9]>(); // expected-error{{no matching function for call to 'foo'}}
+  foo<char[20]>(); // expected-error{{no matching function for call to 'foo'}}
+}
\ No newline at end of file
Index: test/CXX/concepts-ts/dcl/dcl.decl/p3.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/dcl/dcl.decl/p3.cpp
@@ -0,0 +1,9 @@
+// RUN:  %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+
+void f1(int a) requires true; // OK
+auto f2(int a) -> bool requires true; // OK
+auto f3(int a) requires true -> bool; // expected-error{{trailing return type must come before trailing requires clause}}
+void (*pf)() requires true; // expected-error{{trailing requires clause can only be used when declaring a function}}
+void g1(int (*dsdads)() requires false); // expected-error{{trailing requires clause can only be used when declaring a function}}
+void g2(int (*(*dsdads)())() requires true); // expected-error{{trailing requires clause can only be used when declaring a function}}
+void g3(int (*(*dsdads)(int) requires true)() ); // expected-error{{trailing requires clause can only be used when declaring a function}}
\ No newline at end of file
Index: test/CXX/concepts-ts/dcl.dcl/lit.cfg.py
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/dcl.dcl/lit.cfg.py
@@ -1,26 +0,0 @@
-# -*- Python -*-
-
-import os
-import lit.formats
-
-from lit.llvm import llvm_config
-
-# Configuration file for the 'lit' test runner.
-
-# name: The name of this test suite.
-config.name = 'Clang-Concepts-TS-Unsupported'
-
-# testFormat: The test format to use to interpret tests.
-#
-# For now we require '&&' between commands, until they get globally killed and
-# the test runner updated.
-config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell)
-
-# suffixes: A list of file extensions to treat as test files.
-config.suffixes = ['.c', '.cpp', '.cppm', '.m', '.mm', '.cu',
-                   '.ll', '.cl', '.s', '.S', '.modulemap', '.test', '.rs']
-
-config.unsupported = True
-
-# test_source_root: The root path where tests are located.
-config.test_source_root = os.path.dirname(__file__)
Index: test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p7.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p7.cpp
@@ -1,18 +0,0 @@
-// RUN:  %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s
-
-template <typename T> concept bool FCEI() { return true; } // expected-note {{previous declaration is here}} expected-note {{previous declaration is here}}
-template bool FCEI<int>(); // expected-error {{function concept cannot be explicitly instantiated}}
-extern template bool FCEI<double>(); // expected-error {{function concept cannot be explicitly instantiated}}
-
-template <typename T> concept bool FCES() { return true; } // expected-note {{previous declaration is here}}
-template <> bool FCES<int>() { return true; } // expected-error {{function concept cannot be explicitly specialized}}
-
-template <typename T> concept bool VC { true }; // expected-note {{previous declaration is here}} expected-note {{previous declaration is here}}
-template bool VC<int>; // expected-error {{variable concept cannot be explicitly instantiated}}
-extern template bool VC<double>; // expected-error {{variable concept cannot be explicitly instantiated}}
-
-template <typename T> concept bool VCES { true }; // expected-note {{previous declaration is here}}
-template <> bool VCES<int> { true }; // expected-error {{variable concept cannot be explicitly specialized}}
-
-template <typename T> concept bool VCPS { true }; // expected-note {{previous declaration is here}}
-template <typename T> bool VCPS<T *> { true }; // expected-error {{variable concept cannot be partially specialized}}
Index: test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p6.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p6.cpp
@@ -1,25 +0,0 @@
-// RUN:  %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s
-
-template<typename T>
-concept bool vc { true };
-
-template<typename T>
-struct B { typedef bool Boolean; };
-
-template<int N>
-B<void>::Boolean concept vctb(!0);
-
-template<typename T>
-concept const bool vctc { true }; // expected-error {{declared type of variable concept must be 'bool'}}
-
-template<typename T>
-concept int vcti { 5 }; // expected-error {{declared type of variable concept must be 'bool'}}
-
-template<typename T>
-concept float vctf { 5.5 }; // expected-error {{declared type of variable concept must be 'bool'}}
-
-template<typename T>
-concept auto vcta { true }; // expected-error {{declared type of variable concept must be 'bool'}}
-
-template<typename T>
-concept decltype(auto) vctd { true }; // expected-error {{declared type of variable concept must be 'bool'}}
Index: test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p5.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p5.cpp
@@ -1,25 +0,0 @@
-// RUN:  %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s
-
-template<typename T>
-concept bool fcpv(void) { return true; }
-
-template<typename T>
-concept bool fcpi(int i = 0) { return true; } // expected-error {{function concept cannot have any parameters}}
-
-template<typename... Ts>
-concept bool fcpp(Ts... ts) { return true; } // expected-error {{function concept cannot have any parameters}}
-
-template<typename T>
-concept bool fcpva(...) { return true; } // expected-error {{function concept cannot have any parameters}}
-
-template<typename T>
-concept const bool fcrtc() { return true; } // expected-error {{declared return type of function concept must be 'bool'}}
-
-template<typename T>
-concept int fcrti() { return 5; } // expected-error {{declared return type of function concept must be 'bool'}}
-
-template<typename T>
-concept float fcrtf() { return 5.5; } // expected-error {{declared return type of function concept must be 'bool'}}
-
-template<typename T>
-concept decltype(auto) fcrtd(void) { return true; } // expected-error {{declared return type of function concept must be 'bool'}}
Index: test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p2.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p2.cpp
@@ -1,13 +0,0 @@
-// RUN:  %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s
-
-template<typename T> concept thread_local bool VCTL = true; // expected-error {{variable concept cannot be declared 'thread_local'}}
-
-template<typename T> concept constexpr bool VCC = true; // expected-error {{variable concept cannot be declared 'constexpr'}}
-
-template<typename T> concept inline bool FCI() { return true; } // expected-error {{function concept cannot be declared 'inline'}}
-
-struct X {
-  template<typename T> concept friend bool FCF() { return true; } // expected-error {{function concept cannot be declared 'friend'}}
-};
-
-template<typename T> concept constexpr bool FCC() { return true; } // expected-error {{function concept cannot be declared 'constexpr'}}
Index: test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p1.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p1.cpp
@@ -1,60 +0,0 @@
-// RUN:  %clang_cc1 -std=c++14 -fconcepts-ts -fcxx-exceptions -x c++ -verify %s
-
-namespace A {
-  template<typename T> concept bool C1() { return true; }
-
-  template<typename T> concept bool C2 = true;
-}
-
-template<typename T> concept bool C3() { return (throw 0, true); }
-static_assert(noexcept(C3<int>()), "function concept should be treated as if noexcept(true) specified");
-
-template<typename T> concept bool D1(); // expected-error {{function concept declaration must be a definition}}
-
-struct B {
-  template<typename T> concept bool D2() { return true; } // expected-error {{concept declarations may only appear in namespace scope}}
-};
-
-struct C {
-  template<typename T> static concept bool D3 = true; // expected-error {{concept declarations may only appear in namespace scope}}
-};
-
-concept bool D4() { return true; } // expected-error {{'concept' can only appear on the definition of a function template or variable template}}
-
-concept bool D5 = true; // expected-error {{'concept' can only appear on the definition of a function template or variable template}}
-
-template<typename T>
-concept bool D6; // expected-error {{variable concept declaration must be initialized}}
-
-template<typename T>
-concept bool D7() throw(int) { return true; } // expected-error {{function concept cannot have exception specification}}
-
-// Tag
-concept class CC1 {}; // expected-error {{'concept' can only appear on the definition of a function template or variable template}}
-concept struct CS1 {}; // expected-error {{'concept' can only appear on the definition of a function template or variable template}}
-concept union CU1 {}; // expected-error {{'concept' can only appear on the definition of a function template or variable template}}
-concept enum CE1 {}; // expected-error {{'concept' can only appear on the definition of a function template or variable template}}
-template <typename T> concept class TCC1 {}; // expected-error {{'concept' can only appear on the definition of a function template or variable template}}
-template <typename T> concept struct TCS1 {}; // expected-error {{'concept' can only appear on the definition of a function template or variable template}}
-template <typename T> concept union TCU1 {}; // expected-error {{'concept' can only appear on the definition of a function template or variable template}}
-typedef concept int CI; // expected-error {{'concept' can only appear on the definition of a function template or variable template}}
-void fpc(concept int i) {} // expected-error {{'concept' can only appear on the definition of a function template or variable template}}
-
-concept bool; // expected-error {{'concept' can only appear on the definition of a function template or variable template}}
-
-template <typename T> concept bool VCEI{ true };
-template concept bool VCEI<int>; // expected-error {{'concept' cannot be applied on an explicit instantiation}}
-extern template concept bool VCEI<int>; // expected-error {{'concept' cannot be applied on an explicit instantiation}}
-
-template <typename T> concept bool VCPS{ true };
-template <typename T> concept bool VCPS<T *>{ true }; // expected-error {{'concept' cannot be applied on an partial specialization}}
-
-template <typename T> concept bool VCES{ true };
-template <> concept bool VCES<int>{ true }; // expected-error {{'concept' cannot be applied on an explicit specialization}}
-
-template <typename T> concept bool FCEI() { return true; }
-template concept bool FCEI<int>(); // expected-error {{'concept' cannot be applied on an explicit instantiation}}
-extern template concept bool FCEI<int>(); // expected-error {{'concept' cannot be applied on an explicit instantiation}}
-
-template <typename T> concept bool FCES() { return true; }
-template <> concept bool FCES<bool>() { return true; } // expected-error {{'concept' cannot be applied on an explicit specialization}}
Index: test/CXX/concepts-ts/class.derived/class.virtual/p6.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/class.derived/class.virtual/p6.cpp
@@ -0,0 +1,12 @@
+// RUN:  %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+
+template<typename T>
+class A {
+  virtual void f1() requires sizeof(T) == 0; // expected-error{{a virtual function must not have a requires clause}}
+  virtual void f2() requires sizeof(T) == 1; // expected-error{{a virtual function must not have a requires clause}}
+};
+
+template<typename T>
+class B : A<T> {
+  virtual void f1() requires sizeof(T) == 0 override {} // expected-error{{a virtual function must not have a requires clause}}
+};
\ No newline at end of file
Index: lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- lib/Serialization/ASTWriterDecl.cpp
+++ lib/Serialization/ASTWriterDecl.cpp
@@ -538,6 +538,10 @@
   Record.push_back(D->IsLateTemplateParsed);
   Record.push_back(D->getLinkageInternal());
   Record.AddSourceLocation(D->getLocEnd());
+  Expr *RC = D->getTrailingRequiresClause();
+  Record.push_back(RC != nullptr);
+  if (RC)
+    Record.AddStmt(RC);
 
   Record.push_back(D->getTemplatedKind());
   switch (D->getTemplatedKind()) {
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -796,6 +796,9 @@
   FD->IsLateTemplateParsed = Record.readInt();
   FD->setCachedLinkage(Linkage(Record.readInt()));
   FD->EndRangeLoc = ReadSourceLocation();
+  bool HasTrailingRequiresClause = Record.readInt();
+  if (HasTrailingRequiresClause)
+    FD->TrailingRequiresClause = Record.readExpr();
 
   switch ((FunctionDecl::TemplatedKind)Record.readInt()) {
   case FunctionDecl::TK_NonTemplate:
Index: lib/Sema/SemaTemplateVariadic.cpp
===================================================================
--- lib/Sema/SemaTemplateVariadic.cpp
+++ lib/Sema/SemaTemplateVariadic.cpp
@@ -877,9 +877,13 @@
 
       if (Chunk.Fun.hasTrailingReturnType()) {
         QualType T = Chunk.Fun.getTrailingReturnType().get();
-	if (!T.isNull() && T->containsUnexpandedParameterPack())
-	  return true;
+	    if (!T.isNull() && T->containsUnexpandedParameterPack())
+	      return true;
       }
+
+      if (Chunk.Fun.hasTrailingRequiresClause()
+          &&Chunk.Fun.TrailingRequiresClause->containsUnexpandedParameterPack())
+          return true;
       break;
 
     case DeclaratorChunk::MemberPointer:
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1634,6 +1634,17 @@
       return nullptr;
   }
 
+  Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
+  if (TrailingRequiresClause) {
+    ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,
+                                           TemplateArgs);
+    if (!SubstRC.isUsable() || SubstRC.isInvalid())
+      return nullptr;
+    TrailingRequiresClause = SubstRC.get();
+    if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause))
+      return nullptr;
+  }
+
   // If we're instantiating a local function declaration, put the result
   // in the enclosing namespace; otherwise we need to find the instantiated
   // context.
@@ -1692,6 +1703,9 @@
       Params[P]->setOwningFunction(Function);
   Function->setParams(Params);
 
+  if (TrailingRequiresClause)
+    Function->setTrailingRequiresClause(TrailingRequiresClause);
+
   if (TemplateParams) {
     // Our resulting instantiation is actually a function template, since we
     // are substituting only the outer template parameters. For example, given
@@ -1944,6 +1958,17 @@
       return nullptr;
   }
 
+  Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
+  if (TrailingRequiresClause) {
+    ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,
+                                           TemplateArgs);
+    if (!SubstRC.isUsable() || SubstRC.isInvalid())
+      return nullptr;
+    TrailingRequiresClause = SubstRC.get();
+    if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause))
+      return nullptr;
+  }
+
   DeclContext *DC = Owner;
   if (isFriend) {
     if (QualifierLoc) {
@@ -1973,27 +1998,31 @@
                                         StartLoc, NameInfo, T, TInfo,
                                         Constructor->isExplicit(),
                                         Constructor->isInlineSpecified(),
-                                        false, Constructor->isConstexpr());
+                                        false, Constructor->isConstexpr(),
+                                        InheritedConstructor(),
+                                        TrailingRequiresClause);
     Method->setRangeEnd(Constructor->getLocEnd());
   } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
     Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
                                        StartLoc, NameInfo, T, TInfo,
                                        Destructor->isInlineSpecified(),
-                                       false);
+                                       false, TrailingRequiresClause);
     Method->setRangeEnd(Destructor->getLocEnd());
   } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
     Method = CXXConversionDecl::Create(SemaRef.Context, Record,
                                        StartLoc, NameInfo, T, TInfo,
                                        Conversion->isInlineSpecified(),
                                        Conversion->isExplicit(),
                                        Conversion->isConstexpr(),
-                                       Conversion->getLocEnd());
+                                       Conversion->getLocEnd(),
+                                       TrailingRequiresClause);
   } else {
     StorageClass SC = D->isStatic() ? SC_Static : SC_None;
     Method = CXXMethodDecl::Create(SemaRef.Context, Record,
                                    StartLoc, NameInfo, T, TInfo,
                                    SC, D->isInlineSpecified(),
-                                   D->isConstexpr(), D->getLocEnd());
+                                   D->isConstexpr(), D->getLocEnd(),
+                                   TrailingRequiresClause);
   }
 
   if (D->isInlined())
Index: lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- lib/Sema/SemaTemplateDeduction.cpp
+++ lib/Sema/SemaTemplateDeduction.cpp
@@ -3359,7 +3359,7 @@
 
     DeclAccessPair DAP;
     if (FunctionDecl *Viable =
-            S.resolveAddressOfOnlyViableOverloadCandidate(Arg, DAP))
+            S.resolveAddressOfSingleOverloadCandidate(Arg, DAP))
       return GetTypeOfFunction(S, R, Viable);
 
     return QualType();
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -1212,7 +1212,20 @@
     return NewTarget != OldTarget;
   }
 
-  // TODO: Concepts: Check function trailing requires clauses here.
+  Expr *NewRC = New->getTrailingRequiresClause(),
+       *OldRC = Old->getTrailingRequiresClause();
+  if ((NewRC != nullptr) != (OldRC != nullptr))
+    // RC are most certainly different - these are overloads.
+    return true;
+
+  if (NewRC) {
+    llvm::FoldingSetNodeID NewID, OldID;
+    NewRC->Profile(NewID, Context, /*Canonical=*/true);
+    OldRC->Profile(OldID, Context, /*Canonical=*/true);
+    if (NewID != OldID)
+      // RCs are not equivalent - these are overloads.
+      return true;
+  }
 
   // The signatures match; this is not an overload.
   return false;
@@ -6095,6 +6108,21 @@
     Candidate.FailureKind = ovl_fail_ext_disabled;
     return;
   }
+
+  Expr *RequiresClause = Function->getTrailingRequiresClause();
+  if (LangOpts.ConceptsTS && RequiresClause) {
+    EnterExpressionEvaluationContext Eval(*this,
+                                ExpressionEvaluationContext::ConstantEvaluated);
+    bool Satisfied = false;
+    bool Success = RequiresClause->EvaluateAsBooleanCondition(Satisfied,
+                                                              Context);
+    assert(Success && "Constraint expression must be evaluable - this should "
+                      "have been checked earlier.");
+    if (!Satisfied) {
+      Candidate.Viable = false;
+      Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
+    }
+  }
 }
 
 ObjCMethodDecl *
@@ -6600,6 +6628,21 @@
     Candidate.DeductionFailure.Data = FailedAttr;
     return;
   }
+
+  Expr *RequiresClause = Method->getTrailingRequiresClause();
+  if (LangOpts.ConceptsTS && RequiresClause) {
+    EnterExpressionEvaluationContext Eval(*this,
+                                ExpressionEvaluationContext::ConstantEvaluated);
+    bool Satisfied = false;
+    bool Success = RequiresClause->EvaluateAsBooleanCondition(Satisfied,
+                                                              Context);
+    assert(Success && "Constraint expression must be evaluable - this should "
+                      "have been checked earlier.");
+    if (!Satisfied) {
+      Candidate.Viable = false;
+      Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
+    }
+  }
 }
 
 /// \brief Add a C++ member function template as a candidate to the candidate
@@ -9093,6 +9136,20 @@
       return Cmp == Comparison::Better;
   }
 
+  if (Cand1.Function && Cand2.Function) {
+    Expr *RC1 = Cand1.Function->getTrailingRequiresClause();
+    Expr *RC2 = Cand2.Function->getTrailingRequiresClause();
+    if (RC1 && RC2) {
+      bool MoreConstrained1 = S.IsMoreConstrained(Cand1.Function, RC1,
+                                                  Cand2.Function, RC2);
+      bool MoreConstrained2 = S.IsMoreConstrained(Cand2.Function, RC2,
+                                                  Cand1.Function, RC1);
+      if (MoreConstrained1 != MoreConstrained2)
+        return MoreConstrained1;
+    } else if (RC1 || RC2)
+      return RC1 != nullptr;
+  }
+
   if (S.getLangOpts().CUDA && Cand1.Function && Cand2.Function) {
     FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext);
     return S.IdentifyCUDAPreference(Caller, Cand1.Function) >
@@ -9371,6 +9428,25 @@
     return false;
   }
 
+  if (const Expr *RC = FD->getTrailingRequiresClause()) {
+    EnterExpressionEvaluationContext Eval(S,
+                        Sema::ExpressionEvaluationContext::ConstantEvaluated);
+    bool Satisfied = false;
+    bool Success = RC->EvaluateAsBooleanCondition(Satisfied, S.Context);
+    if (!Success || !Satisfied) {
+      if (Complain) {
+        if (InOverloadResolution)
+          S.Diag(FD->getLocStart(),
+                 diag::note_ovl_candidate_unsatisfied_constraints);
+        else
+          S.Diag(Loc, diag::err_addrof_function_constraints_not_satisfied)
+              << FD;
+        S.DiagnoseUnsatisfiedConstraint(const_cast<Expr*>(RC));
+      }
+      return false;
+    }
+  }
+
   auto I = llvm::find_if(FD->parameters(), [](const ParmVarDecl *P) {
     return P->hasAttr<PassObjectSizeAttr>();
   });
@@ -10233,6 +10309,17 @@
     assert(!Available);
     break;
   }
+
+  case ovl_fail_constraints_not_satisfied: {
+    std::string Description;
+    OverloadCandidateKind FnKind =
+                 ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Description);
+    S.Diag(Fn->getLocation(),
+           diag::note_ovl_candidate_constraints_not_satisfied)
+            << (unsigned) FnKind;
+    S.DiagnoseUnsatisfiedConstraint(Fn->getTrailingRequiresClause());
+    break;
+  }
   }
 }
 
@@ -11221,13 +11308,14 @@
 /// resolve that function to a single function that can have its address taken.
 /// This will modify `Pair` iff it returns non-null.
 ///
-/// This routine can only realistically succeed if all but one candidates in the
-/// overload set for SrcExpr cannot have their addresses taken.
+/// This routine can only succeed if from all of the candidates in the overload
+/// set for SrcExpr that can have their addresses taken, there is one candidate
+/// that is more constrained than the rest.
 FunctionDecl *
-Sema::resolveAddressOfOnlyViableOverloadCandidate(Expr *E,
-                                                  DeclAccessPair &Pair) {
+Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) {
   OverloadExpr::FindResult R = OverloadExpr::find(E);
   OverloadExpr *Ovl = R.Expression;
+  bool IsResultAmbiguous = false;
   FunctionDecl *Result = nullptr;
   DeclAccessPair DAP;
   // Don't use the AddressOfResolver because we're specifically looking for
@@ -11241,32 +11329,50 @@
     if (!checkAddressOfFunctionIsAvailable(FD))
       continue;
 
-    // We have more than one result; quit.
-    if (Result)
-      return nullptr;
+    // We have more than one result - see if it is more constrained than the
+    // previous one.
+    if (Result) {
+      bool ResultMoreConstrained = IsMoreConstrained(Result,
+                                           Result->getTrailingRequiresClause(),
+                                           FD, FD->getTrailingRequiresClause());
+      bool FDMoreConstrained = IsMoreConstrained(FD,
+                                           FD->getTrailingRequiresClause(),
+                                           Result,
+                                           Result->getTrailingRequiresClause());
+      if (ResultMoreConstrained == FDMoreConstrained) {
+        IsResultAmbiguous = true;
+        continue;
+      } else if (ResultMoreConstrained)
+        continue;
+      // FD is more constrained replace Result with it.
+    }
+    IsResultAmbiguous = false;
     DAP = I.getPair();
     Result = FD;
   }
 
+  if (IsResultAmbiguous)
+    return nullptr;
+
   if (Result)
     Pair = DAP;
   return Result;
 }
 
 /// \brief Given an overloaded function, tries to turn it into a non-overloaded
-/// function reference using resolveAddressOfOnlyViableOverloadCandidate. This
-/// will perform access checks, diagnose the use of the resultant decl, and, if
+/// function reference using resolveAddressOfSingleOverloadCandidate. This will
+/// perform access checks, diagnose the use of the resultant decl, and, if
 /// requested, potentially perform a function-to-pointer decay.
 ///
-/// Returns false if resolveAddressOfOnlyViableOverloadCandidate fails.
+/// Returns false if resolveAddressOfSingleOverloadCandidate fails.
 /// Otherwise, returns true. This may emit diagnostics and return true.
-bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate(
+bool Sema::resolveAndFixAddressOfSingleOverloadCandidate(
     ExprResult &SrcExpr, bool DoFunctionPointerConverion) {
   Expr *E = SrcExpr.get();
   assert(E->getType() == Context.OverloadTy && "SrcExpr must be an overload");
 
   DeclAccessPair DAP;
-  FunctionDecl *Found = resolveAddressOfOnlyViableOverloadCandidate(E, DAP);
+  FunctionDecl *Found = resolveAddressOfSingleOverloadCandidate(E, DAP);
   if (!Found)
     return false;
 
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -2713,6 +2713,24 @@
     return true;
   }
 
+  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+    if (Expr *RC = FD->getTrailingRequiresClause()) {
+      EnterExpressionEvaluationContext Eval(S,
+                          Sema::ExpressionEvaluationContext::ConstantEvaluated);
+      bool Satisfied = false;
+      bool Success = RC->EvaluateAsBooleanCondition(Satisfied, S.Context);
+      assert(Success && "Constraint expression must be evaluable - this should "
+                        "have been checked earlier.");
+      if (!Satisfied) {
+        S.Diag(Loc,
+               diag::err_reference_to_function_with_unsatisfied_constraints)
+            << D;
+        S.DiagnoseUnsatisfiedConstraint(RC);
+        return true;
+      }
+    }
+  }
+
   return false;
 }
 
@@ -15965,7 +15983,7 @@
     // No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization
     // leaves Result unchanged on failure.
     Result = E;
-    if (resolveAndFixAddressOfOnlyViableOverloadCandidate(Result))
+    if (resolveAndFixAddressOfSingleOverloadCandidate(Result))
       return Result;
 
     // If that failed, try to recover with a call.
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -10552,7 +10552,8 @@
       Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo,
       BaseCtor->isExplicit(), /*Inline=*/true,
       /*ImplicitlyDeclared=*/true, Constexpr,
-      InheritedConstructor(Shadow, BaseCtor));
+      InheritedConstructor(Shadow, BaseCtor),
+      BaseCtor->getTrailingRequiresClause());
   if (Shadow->isInvalidDecl())
     DerivedCtor->setInvalidDecl();
 
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -6709,7 +6709,8 @@
                                  FD->getType(), FD->getTypeSourceInfo(),
                                  SC_None, false/*isInlineSpecified*/,
                                  FD->hasPrototype(),
-                                 false/*isConstexprSpecified*/);
+                                 false/*isConstexprSpecified*/,
+                                 FD->getTrailingRequiresClause());
     NewD = NewFD;
 
     if (FD->getQualifier())
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -7845,6 +7845,10 @@
 
   bool isExplicit = D.getDeclSpec().isExplicitSpecified();
   bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
+  Expr *TrailingRequiresClause = D.isFunctionDeclarator()
+                                 && D.hasTrailingRequiresClause() ?
+                             D.getFunctionTypeInfo().getTrailingRequiresClause()
+                                 : nullptr;
 
   // Check that the return type is not an abstract class type.
   // For record types, this is done by the AbstractClassUsageDiagnoser once
@@ -7865,7 +7869,8 @@
                                       D.getLocStart(), NameInfo,
                                       R, TInfo, isExplicit, isInline,
                                       /*isImplicitlyDeclared=*/false,
-                                      isConstexpr);
+                                      isConstexpr, InheritedConstructor(),
+                                      TrailingRequiresClause);
 
   } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
     // This is a C++ destructor declaration.
@@ -7876,7 +7881,8 @@
                                         SemaRef.Context, Record,
                                         D.getLocStart(),
                                         NameInfo, R, TInfo, isInline,
-                                        /*isImplicitlyDeclared=*/false);
+                                        /*isImplicitlyDeclared=*/false,
+                                        TrailingRequiresClause);
 
       // If the class is complete, then we now create the implicit exception
       // specification. If the class is incomplete or dependent, we can't do
@@ -7900,7 +7906,8 @@
                                   D.getLocStart(),
                                   D.getIdentifierLoc(), Name, R, TInfo,
                                   SC, isInline,
-                                  /*hasPrototype=*/true, isConstexpr);
+                                  /*hasPrototype=*/true, isConstexpr,
+                                  TrailingRequiresClause);
     }
 
   } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
@@ -7915,7 +7922,8 @@
     return CXXConversionDecl::Create(SemaRef.Context, cast<CXXRecordDecl>(DC),
                                      D.getLocStart(), NameInfo,
                                      R, TInfo, isInline, isExplicit,
-                                     isConstexpr, SourceLocation());
+                                     isConstexpr, SourceLocation(),
+                                     TrailingRequiresClause);
 
   } else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
     SemaRef.CheckDeductionGuideDeclarator(D, R, SC);
@@ -7941,7 +7949,8 @@
                                                cast<CXXRecordDecl>(DC),
                                                D.getLocStart(), NameInfo, R,
                                                TInfo, SC, isInline,
-                                               isConstexpr, SourceLocation());
+                                               isConstexpr, SourceLocation(),
+                                               TrailingRequiresClause);
     IsVirtualOkay = !Ret->isStatic();
     return Ret;
   } else {
@@ -7956,7 +7965,8 @@
     return FunctionDecl::Create(SemaRef.Context, DC,
                                 D.getLocStart(),
                                 NameInfo, R, TInfo, SC, isInline,
-                                true/*HasPrototype*/, isConstexpr);
+                                true/*HasPrototype*/, isConstexpr,
+                                TrailingRequiresClause);
   }
 }
 
@@ -8364,6 +8374,11 @@
         Diag(D.getDeclSpec().getVirtualSpecLoc(),
              diag::err_virtual_member_function_template)
           << FixItHint::CreateRemoval(D.getDeclSpec().getVirtualSpecLoc());
+      } else if (D.hasTrailingRequiresClause()) {
+        // C++2a [class.virtual]p6
+        // A virtual method shall not have a requires-clause.
+        Diag(NewFD->getTrailingRequiresClause()->getLocStart(),
+             diag::err_constrained_virtual_method);
       } else {
         // Okay: Add virtual to the method.
         NewFD->setVirtualAsWritten(true);
Index: lib/Sema/SemaCast.cpp
===================================================================
--- lib/Sema/SemaCast.cpp
+++ lib/Sema/SemaCast.cpp
@@ -1907,7 +1907,7 @@
   // No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization
   // preserves Result.
   Result = E;
-  if (!Self.resolveAndFixAddressOfOnlyViableOverloadCandidate(
+  if (!Self.resolveAndFixAddressOfSingleOverloadCandidate(
           Result, /*DoFunctionPointerConversion=*/true))
     return false;
   return Result.isUsable();
Index: lib/Sema/DeclSpec.cpp
===================================================================
--- lib/Sema/DeclSpec.cpp
+++ lib/Sema/DeclSpec.cpp
@@ -178,7 +178,8 @@
                                              SourceLocation LocalRangeBegin,
                                              SourceLocation LocalRangeEnd,
                                              Declarator &TheDeclarator,
-                                             TypeResult TrailingReturnType) {
+                                             TypeResult TrailingReturnType,
+                                             Expr *TrailingRequiresClause) {
   assert(!(TypeQuals & DeclSpec::TQ_atomic) &&
          "function cannot have _Atomic qualifier");
 
@@ -212,6 +213,7 @@
   I.Fun.HasTrailingReturnType   = TrailingReturnType.isUsable() ||
                                   TrailingReturnType.isInvalid();
   I.Fun.TrailingReturnType      = TrailingReturnType.get();
+  I.Fun.TrailingRequiresClause  = TrailingRequiresClause;
 
   assert(I.Fun.TypeQuals == TypeQuals && "bitfield overflow");
   assert(I.Fun.ExceptionSpecType == ESpecType && "bitfield overflow");
Index: lib/Parse/ParseTentative.cpp
===================================================================
--- lib/Parse/ParseTentative.cpp
+++ lib/Parse/ParseTentative.cpp
@@ -949,6 +949,14 @@
       // direct-declarator '[' constant-expression[opt] ']'
       // direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
       TPR = TryParseBracketDeclarator();
+    } else if (Tok.is(tok::kw_requires)) {
+      // declarator requires-clause
+      // A requires clause indicates a function declaration.
+      if (ParenCount) {
+        SkipUntil(tok::l_paren);
+      } else {
+        TPR = TPResult::True;
+      }
     } else {
       break;
     }
@@ -1852,7 +1860,6 @@
 ///   'throw' '(' type-id-list[opt] ')'
 ///
 Parser::TPResult Parser::TryParseFunctionDeclarator() {
-
   // The '(' is already parsed.
 
   TPResult TPR = TryParseParameterDeclarationClause();
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp
+++ lib/Parse/ParseDecl.cpp
@@ -5925,7 +5925,8 @@
 ///
 /// For C++, after the parameter-list, it also parses the cv-qualifier-seq[opt],
 /// (C++11) ref-qualifier[opt], exception-specification[opt],
-/// (C++11) attribute-specifier-seq[opt], and (C++11) trailing-return-type[opt].
+/// (C++11) attribute-specifier-seq[opt], (C++11) trailing-return-type[opt] and
+/// (C++2a) the trailing requires-clause.
 ///
 /// [C++11] exception-specification:
 ///           dynamic-exception-specification
@@ -5963,6 +5964,7 @@
   CachedTokens *ExceptionSpecTokens = nullptr;
   ParsedAttributesWithRange FnAttrs(AttrFactory);
   TypeResult TrailingReturnType;
+  ExprResult TrailingRequiresClause;
 
   /* LocalEndLoc is the end location for the local FunctionTypeLoc.
      EndLoc is the end location for the function declarator.
@@ -6084,14 +6086,77 @@
 
       // Parse trailing-return-type[opt].
       LocalEndLoc = EndLoc;
-      if (getLangOpts().CPlusPlus11 && Tok.is(tok::arrow)) {
+      auto ParseTrailingReturn = [&] {
         Diag(Tok, diag::warn_cxx98_compat_trailing_return_type);
         if (D.getDeclSpec().getTypeSpecType() == TST_auto)
           StartLoc = D.getDeclSpec().getTypeSpecTypeLoc();
         LocalEndLoc = Tok.getLocation();
         SourceRange Range;
         TrailingReturnType = ParseTrailingReturnType(Range);
         EndLoc = Range.getEnd();
+      };
+      if (getLangOpts().CPlusPlus11 && Tok.is(tok::arrow)) {
+        ParseTrailingReturn();
+      }
+      // Parse trailing requires-clause[opt].
+      if (getLangOpts().ConceptsTS && Tok.is(tok::kw_requires)) {
+        LocalEndLoc = Tok.getLocation();
+        ConsumeToken();
+
+        TentativeParsingAction TPA(*this);
+        Diags.setSuppressAllDiagnostics(true);
+        TrailingRequiresClause = ParseConstraintExpression();
+        Diags.setSuppressAllDiagnostics(false);
+
+        if (TrailingRequiresClause.isUsable()
+            && !TrailingRequiresClause.isInvalid()) {
+          TPA.Commit();
+          EndLoc = TrailingRequiresClause.get()->getLocEnd();
+
+          // Did the user swap the trailing return type and requires clause?
+          if (getLangOpts().CPlusPlus11 && Tok.is(tok::arrow)) {
+            Diag(Tok, diag::err_requires_clause_must_come_after_trailing_return);
+            // Parse it anyway
+            ParseTrailingReturn();
+          }
+          if (!D.isFunctionDeclaratorAFunctionDeclaration()) {
+            Diag(LocalEndLoc,
+              diag::err_requires_clause_on_declarator_not_declaring_a_function);
+          }
+
+        } else {
+          // Did the user swap the trailing return type and requires clause?
+          SourceLocation FailureLocation = Tok.getLocation();
+          TPA.Revert();
+          bool Found = false;
+          while (true) {
+            if (Tok.is(tok::arrow)) {
+              SourceLocation ArrowLoc = Tok.getLocation();
+              TentativeParsingAction TPA(*this);
+              Diags.setSuppressAllDiagnostics(true);
+              ParseTrailingReturn();
+              Diags.setSuppressAllDiagnostics(false);
+
+              if (TrailingReturnType.isUsable()
+                  && !TrailingReturnType.isInvalid()) {
+                TPA.Commit();
+                Diag(ArrowLoc,
+                     diag::err_requires_clause_must_come_after_trailing_return);
+                EndLoc = Tok.getLocation();
+                Found = true;
+                break;
+              }
+              TPA.Revert();
+            }
+            ConsumeToken();
+            if (Tok.getLocation() == FailureLocation)
+              break;
+          }
+          if (!Found)
+            // User did not swap a trailing return and a trailing requires clause.
+            // Re-parse the thing and display the original error message.
+            ParseConstraintExpression();
+        }
       }
     } else if (standardAttributesAllowed()) {
       MaybeParseCXX11Attributes(FnAttrs);
@@ -6134,7 +6199,9 @@
                                              ExceptionSpecTokens,
                                              DeclsInPrototype,
                                              StartLoc, LocalEndLoc, D,
-                                             TrailingReturnType),
+                                             TrailingReturnType,
+                                             TrailingRequiresClause.isUsable() ?
+                                        TrailingRequiresClause.get() : nullptr),
                 FnAttrs, EndLoc);
 }
 
Index: lib/AST/ODRHash.cpp
===================================================================
--- lib/AST/ODRHash.cpp
+++ lib/AST/ODRHash.cpp
@@ -320,6 +320,7 @@
     }
 
     AddQualType(D->getReturnType());
+    AddStmt(D->getTrailingRequiresClause());
 
     Inherited::VisitFunctionDecl(D);
   }
Index: lib/AST/DeclTemplate.cpp
===================================================================
--- lib/AST/DeclTemplate.cpp
+++ lib/AST/DeclTemplate.cpp
@@ -146,16 +146,31 @@
 
 } // namespace clang
 
+// Create a constraint expression as the conjunction (the "and") of two other
+// constraint expressions.
+static Expr *CreateConstraintConjunction(ASTContext &C, Expr *A, Expr *B) {
+  if (!A) {
+    return B;
+  }
+  if (B) {
+    return new (C) BinaryOperator(A, B, BO_LAnd, C.BoolTy, VK_RValue,
+                                  OK_Ordinary, /*opLoc=*/SourceLocation(),
+                                  FPOptions());
+  }
+  return A;
+}
+
 static ConstrainedTemplateDeclInfo *
-collectAssociatedConstraints(ASTContext& C, TemplateParameterList *Params) {
+collectAssociatedConstraints(ASTContext &C, TemplateParameterList *Params,
+                             Expr *TrailingRequiresClause = nullptr) {
   // TODO: Instead of calling getRequiresClause - write and call a
   // TemplateParameterList member function calculateAssociatedConstraints, which
   // will also fetch constraint-expressions from constrained-parameters.
-  Expr *AssociatedConstraints = Params->getRequiresClause();
-  // TODO: Collect function requires clause, if any.
-  if (AssociatedConstraints) {
+  Expr *TotalAC = CreateConstraintConjunction(C, Params->getRequiresClause(),
+                                              TrailingRequiresClause);
+  if (TotalAC) {
     ConstrainedTemplateDeclInfo *CTDI = new (C) ConstrainedTemplateDeclInfo;
-    CTDI->setAssociatedConstraints(AssociatedConstraints);
+    CTDI->setAssociatedConstraints(TotalAC);
     CTDI->setTemplateParameters(Params);
     return CTDI;
   }
@@ -170,12 +185,14 @@
                                   llvm::PointerIntPair<
                                     llvm::PointerUnion<TemplateParameterList *,
                                                  ConstrainedTemplateDeclInfo *>,
-                                    1, bool>& TemplateParamsMember) {
+                                    1, bool>& TemplateParamsMember,
+                                  Expr *TrailingRequiresClause = nullptr) {
   if (!TemplateParamsMember.getInt()) {
     TemplateParamsMember.setInt(true);
     ConstrainedTemplateDeclInfo *CTDI =
       collectAssociatedConstraints(C, TemplateParamsMember.getPointer()
-                                        .get<TemplateParameterList*>());
+                                        .get<TemplateParameterList*>(),
+                                   TrailingRequiresClause);
     if (CTDI) {
       TemplateParamsMember.setPointer(CTDI);
       return CTDI->getAssociatedConstraints();
@@ -199,8 +216,11 @@
 
 
 Expr *TemplateDecl::getAssociatedConstraints() {
-  return getOrCollectAssociatedConstraints(getASTContext(),
-                        cast<TemplateDecl>(getCanonicalDecl())->TemplateParams);
+  FunctionDecl *Func = dyn_cast_or_null<FunctionDecl>(TemplatedDecl);
+  return getOrCollectAssociatedConstraints(
+            getASTContext(),
+            cast<TemplateDecl>(getCanonicalDecl())->TemplateParams,
+            Func ? Func->getTrailingRequiresClause() : nullptr);
 }
 
 void TemplateDecl::anchor() {}
Index: lib/AST/DeclPrinter.cpp
===================================================================
--- lib/AST/DeclPrinter.cpp
+++ lib/AST/DeclPrinter.cpp
@@ -694,6 +694,11 @@
       Proto.clear();
     }
     Out << Proto;
+
+    if (Expr *TrailingRequiresClause = D->getTrailingRequiresClause()) {
+      Out << " requires ";
+      TrailingRequiresClause->printPretty(Out, nullptr, SubPolicy, Indentation);
+    }
   } else {
     Ty.print(Out, Policy, Proto);
   }
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -1698,16 +1698,18 @@
                       const DeclarationNameInfo &NameInfo,
                       QualType T, TypeSourceInfo *TInfo,
                       StorageClass SC, bool isInline,
-                      bool isConstexpr, SourceLocation EndLocation) {
+                      bool isConstexpr, SourceLocation EndLocation,
+                      Expr *TrailingRequiresClause) {
   return new (C, RD) CXXMethodDecl(CXXMethod, C, RD, StartLoc, NameInfo,
                                    T, TInfo, SC, isInline, isConstexpr,
-                                   EndLocation);
+                                   EndLocation, TrailingRequiresClause);
 }
 
 CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
   return new (C, ID) CXXMethodDecl(CXXMethod, C, nullptr, SourceLocation(),
                                    DeclarationNameInfo(), QualType(), nullptr,
-                                   SC_None, false, false, SourceLocation());
+                                   SC_None, false, false, SourceLocation(),
+                                   nullptr);
 }
 
 CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
@@ -2048,7 +2050,7 @@
   unsigned Extra = additionalSizeToAlloc<InheritedConstructor>(Inherited);
   auto *Result = new (C, ID, Extra) CXXConstructorDecl(
       C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
-      false, false, false, false, InheritedConstructor());
+      false, false, false, false, InheritedConstructor(), nullptr);
   Result->IsInheritingConstructor = Inherited;
   return Result;
 }
@@ -2060,15 +2062,16 @@
                            QualType T, TypeSourceInfo *TInfo,
                            bool isExplicit, bool isInline,
                            bool isImplicitlyDeclared, bool isConstexpr,
-                           InheritedConstructor Inherited) {
+                           InheritedConstructor Inherited,
+                           Expr *TrailingRequiresClause) {
   assert(NameInfo.getName().getNameKind()
          == DeclarationName::CXXConstructorName &&
          "Name must refer to a constructor");
   unsigned Extra =
       additionalSizeToAlloc<InheritedConstructor>(Inherited ? 1 : 0);
   return new (C, RD, Extra) CXXConstructorDecl(
       C, RD, StartLoc, NameInfo, T, TInfo, isExplicit, isInline,
-      isImplicitlyDeclared, isConstexpr, Inherited);
+      isImplicitlyDeclared, isConstexpr, Inherited, TrailingRequiresClause);
 }
 
 CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const {
@@ -2189,20 +2192,22 @@
 CXXDestructorDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
   return new (C, ID)
       CXXDestructorDecl(C, nullptr, SourceLocation(), DeclarationNameInfo(),
-                        QualType(), nullptr, false, false);
+                        QualType(), nullptr, false, false, nullptr);
 }
 
 CXXDestructorDecl *
 CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
                           SourceLocation StartLoc,
                           const DeclarationNameInfo &NameInfo,
                           QualType T, TypeSourceInfo *TInfo,
-                          bool isInline, bool isImplicitlyDeclared) {
+                          bool isInline, bool isImplicitlyDeclared,
+                          Expr *TrailingRequiresClause) {
   assert(NameInfo.getName().getNameKind()
          == DeclarationName::CXXDestructorName &&
          "Name must refer to a destructor");
   return new (C, RD) CXXDestructorDecl(C, RD, StartLoc, NameInfo, T, TInfo,
-                                       isInline, isImplicitlyDeclared);
+                                       isInline, isImplicitlyDeclared,
+                                       TrailingRequiresClause);
 }
 
 void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD, Expr *ThisArg) {
@@ -2222,22 +2227,23 @@
   return new (C, ID) CXXConversionDecl(C, nullptr, SourceLocation(),
                                        DeclarationNameInfo(), QualType(),
                                        nullptr, false, false, false,
-                                       SourceLocation());
+                                       SourceLocation(), nullptr);
 }
 
 CXXConversionDecl *
 CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
                           SourceLocation StartLoc,
                           const DeclarationNameInfo &NameInfo,
                           QualType T, TypeSourceInfo *TInfo,
                           bool isInline, bool isExplicit,
-                          bool isConstexpr, SourceLocation EndLocation) {
+                          bool isConstexpr, SourceLocation EndLocation,
+                          Expr *TrailingRequiresClause) {
   assert(NameInfo.getName().getNameKind()
          == DeclarationName::CXXConversionFunctionName &&
          "Name must refer to a conversion function");
   return new (C, RD) CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo,
                                        isInline, isExplicit, isConstexpr,
-                                       EndLocation);
+                                       EndLocation, TrailingRequiresClause);
 }
 
 bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -4211,18 +4211,20 @@
                                    StorageClass SC,
                                    bool isInlineSpecified,
                                    bool hasWrittenPrototype,
-                                   bool isConstexprSpecified) {
+                                   bool isConstexprSpecified,
+                                   Expr *TrailingRequiresClause) {
   FunctionDecl *New =
       new (C, DC) FunctionDecl(Function, C, DC, StartLoc, NameInfo, T, TInfo,
-                               SC, isInlineSpecified, isConstexprSpecified);
+                               SC, isInlineSpecified, isConstexprSpecified,
+                               TrailingRequiresClause);
   New->HasWrittenPrototype = hasWrittenPrototype;
   return New;
 }
 
 FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
   return new (C, ID) FunctionDecl(Function, C, nullptr, SourceLocation(),
                                   DeclarationNameInfo(), QualType(), nullptr,
-                                  SC_None, false, false);
+                                  SC_None, false, false, nullptr);
 }
 
 BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -2134,7 +2134,9 @@
                                             FromConstructor->isExplicit(),
                                             D->isInlineSpecified(), 
                                             D->isImplicit(),
-                                            D->isConstexpr());
+                                            D->isConstexpr(),
+                                            InheritedConstructor(),
+                                            D->getTrailingRequiresClause());
     if (unsigned NumInitializers = FromConstructor->getNumCtorInitializers()) {
       SmallVector<CXXCtorInitializer *, 4> CtorInitializers;
       for (CXXCtorInitializer *I : FromConstructor->inits()) {
@@ -2157,7 +2159,8 @@
                                            InnerLocStart,
                                            NameInfo, T, TInfo,
                                            D->isInlineSpecified(),
-                                           D->isImplicit());
+                                           D->isImplicit(),
+                                           D->getTrailingRequiresClause());
   } else if (CXXConversionDecl *FromConversion
                                            = dyn_cast<CXXConversionDecl>(D)) {
     ToFunction = CXXConversionDecl::Create(Importer.getToContext(), 
@@ -2167,23 +2170,26 @@
                                            D->isInlineSpecified(),
                                            FromConversion->isExplicit(),
                                            D->isConstexpr(),
-                                           Importer.Import(D->getLocEnd()));
+                                           Importer.Import(D->getLocEnd()),
+                                           D->getTrailingRequiresClause());
   } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
     ToFunction = CXXMethodDecl::Create(Importer.getToContext(), 
                                        cast<CXXRecordDecl>(DC),
                                        InnerLocStart,
                                        NameInfo, T, TInfo,
                                        Method->getStorageClass(),
                                        Method->isInlineSpecified(),
                                        D->isConstexpr(),
-                                       Importer.Import(D->getLocEnd()));
+                                       Importer.Import(D->getLocEnd()),
+                                       D->getTrailingRequiresClause());
   } else {
     ToFunction = FunctionDecl::Create(Importer.getToContext(), DC,
                                       InnerLocStart,
                                       NameInfo, T, TInfo, D->getStorageClass(),
                                       D->isInlineSpecified(),
                                       D->hasWrittenPrototype(),
-                                      D->isConstexpr());
+                                      D->isConstexpr(),
+                                      D->getTrailingRequiresClause());
   }
 
   // Import the qualifier, if any.
Index: lib/AST/ASTDumper.cpp
===================================================================
--- lib/AST/ASTDumper.cpp
+++ lib/AST/ASTDumper.cpp
@@ -1217,6 +1217,11 @@
     }
   }
 
+  if (const Expr *RequiresClause = D->getTrailingRequiresClause()) {
+    OS << " requires ";
+    dumpStmt(RequiresClause);
+  }
+
   if (D->doesThisDeclarationHaveABody())
     dumpStmt(D->getBody());
 }
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -2856,10 +2856,9 @@
                                      bool *pHadMultipleCandidates = nullptr);
 
   FunctionDecl *
-  resolveAddressOfOnlyViableOverloadCandidate(Expr *E,
-                                              DeclAccessPair &FoundResult);
+  resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &FoundResult);
 
-  bool resolveAndFixAddressOfOnlyViableOverloadCandidate(
+  bool resolveAndFixAddressOfSingleOverloadCandidate(
       ExprResult &SrcExpr, bool DoFunctionPointerConversion = false);
 
   FunctionDecl *
Index: include/clang/Sema/Overload.h
===================================================================
--- include/clang/Sema/Overload.h
+++ include/clang/Sema/Overload.h
@@ -613,6 +613,10 @@
     /// This inherited constructor is not viable because it would slice the
     /// argument.
     ovl_fail_inhctor_slice,
+
+    /// This candidate was not viable because its associated constraints were
+    /// not satisfied.
+    ovl_fail_constraints_not_satisfied
   };
 
   /// A list of implicit conversion sequences for the arguments of an
Index: include/clang/Sema/DeclSpec.h
===================================================================
--- include/clang/Sema/DeclSpec.h
+++ include/clang/Sema/DeclSpec.h
@@ -1329,6 +1329,11 @@
     /// type specified.
     UnionParsedType TrailingReturnType;
 
+    /// \brief The constraint-expression specified by the trailing
+    /// requires-clause, or null if no such clause was specified.
+    Expr *TrailingRequiresClause;
+
+
     /// \brief Reset the parameter list to having zero parameters.
     ///
     /// This is used in various places for error recovery.
@@ -1447,6 +1452,15 @@
 
     /// \brief Get the trailing-return-type for this function declarator.
     ParsedType getTrailingReturnType() const { return TrailingReturnType; }
+
+    /// \brief Determine whether this function declarator had a
+    /// trailing requires-clause.
+    bool hasTrailingRequiresClause() const { return TrailingRequiresClause; }
+
+    /// \brief Get the trailing requires-clause for this function declarator.
+    Expr *getTrailingRequiresClause() const {
+      return TrailingRequiresClause;
+    }
   };
 
   struct BlockPointerTypeInfo : TypeInfoCommon {
@@ -1591,7 +1605,8 @@
                                      SourceLocation LocalRangeEnd,
                                      Declarator &TheDeclarator,
                                      TypeResult TrailingReturnType =
-                                                    TypeResult());
+                                                    TypeResult(),
+                                     Expr *TrailingRequiresClause = nullptr);
 
   /// \brief Return a DeclaratorChunk for a block.
   static DeclaratorChunk getBlockPointer(unsigned TypeQuals,
@@ -2347,6 +2362,16 @@
     return false;
   }
 
+  /// \brief Determine whether a trailing requires clause was written (at any
+  /// level) within this declarator.
+  bool hasTrailingRequiresClause() const {
+    for (const auto &Chunk : type_objects())
+      if (Chunk.Kind == DeclaratorChunk::Function &&
+          Chunk.Fun.hasTrailingRequiresClause())
+        return true;
+    return false;
+  }
+
   /// takeAttributes - Takes attributes from the given parsed-attributes
   /// set and add them to this declarator.
   ///
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2427,6 +2427,10 @@
   "expression would be illegal">;
 def note_could_not_normalize_ill_formed_constraint_reason : Note<
   "because: %0">;
+def err_constrained_virtual_method : Error<
+  "a virtual function must not have a requires clause">;
+def err_reference_to_function_with_unsatisfied_constraints : Error<
+  "invalid reference to function %0 - constraints not satisfied">;
 
 def err_template_different_associated_constraints : Error<
   "associated constraints differ in template redeclaration">;
@@ -3590,6 +3594,9 @@
 def err_addrof_function_disabled_by_enable_if_attr : Error<
     "cannot take address of function %0 because it has one or more "
     "non-tautological enable_if conditions">;
+def err_addrof_function_constraints_not_satisfied : Error<
+    "cannot take address of function %0 because its constraints are not "
+    "satisfied">;
 def note_addrof_ovl_candidate_disabled_by_enable_if_attr : Note<
     "candidate function made ineligible by enable_if">;
 def note_ovl_candidate_deduced_mismatch : Note<
@@ -3827,6 +3834,16 @@
     "call to "
     "%select{__device__|__global__|__host__|__host__ __device__|invalid}1 function from"
     " %select{__device__|__global__|__host__|__host__ __device__|invalid}2 function">;
+def note_ovl_candidate_constraints_not_satisfied : Note<
+    "candidate %select{function|function|constructor|"
+    "function|function|constructor|"
+    "constructor (the implicit default constructor)|"
+    "constructor (the implicit copy constructor)|"
+    "constructor (the implicit move constructor)|"
+    "function (the implicit copy assignment operator)|"
+    "function (the implicit move assignment operator)|"
+    "inherited constructor|"
+    "inherited constructor}0 not viable: constraints not satisfied">;
 def note_implicit_member_target_infer_collision : Note<
     "implicit %select{"
     "default constructor|"
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -278,6 +278,10 @@
 def warn_cxx98_compat_trailing_return_type : Warning<
   "trailing return types are incompatible with C++98">,
   InGroup<CXX98Compat>, DefaultIgnore;
+def err_requires_clause_must_come_after_trailing_return : Error<
+  "trailing return type must come before trailing requires clause">;
+def err_requires_clause_on_declarator_not_declaring_a_function : Error<
+  "trailing requires clause can only be used when declaring a function">;
 def ext_auto_storage_class : ExtWarn<
   "'auto' storage class specifier is not permitted in C++11, and will not "
   "be supported in future releases">, InGroup<DiagGroup<"auto-storage-class">>;
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -1982,6 +1982,11 @@
     }
   }
 
+  // Visit the trailing requires clause, if any.
+  if (Expr *TrailingRequiresClause = D->getTrailingRequiresClause()) {
+    TRY_TO(TraverseStmt(TrailingRequiresClause));
+  }
+
   if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
     // Constructor initializers.
     for (auto *I : Ctor->inits()) {
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h
+++ include/clang/AST/DeclCXX.h
@@ -1969,9 +1969,10 @@
                 SourceLocation StartLoc, const DeclarationNameInfo &NameInfo,
                 QualType T, TypeSourceInfo *TInfo,
                 StorageClass SC, bool isInline,
-                bool isConstexpr, SourceLocation EndLocation)
+                bool isConstexpr, SourceLocation EndLocation,
+                Expr *TrailingRequiresClause = nullptr)
     : FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo,
-                   SC, isInline, isConstexpr) {
+                   SC, isInline, isConstexpr, TrailingRequiresClause) {
     if (EndLocation.isValid())
       setRangeEnd(EndLocation);
   }
@@ -1984,7 +1985,8 @@
                                StorageClass SC,
                                bool isInline,
                                bool isConstexpr,
-                               SourceLocation EndLocation);
+                               SourceLocation EndLocation,
+                               Expr *TrailingRequiresClause = nullptr);
 
   static CXXMethodDecl *CreateDeserialized(ASTContext &C, unsigned ID);
 
@@ -2413,9 +2415,11 @@
                      QualType T, TypeSourceInfo *TInfo,
                      bool isExplicitSpecified, bool isInline,
                      bool isImplicitlyDeclared, bool isConstexpr,
-                     InheritedConstructor Inherited)
+                     InheritedConstructor Inherited,
+                     Expr *TrailingRequiresClause = nullptr)
     : CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
-                    SC_None, isInline, isConstexpr, SourceLocation()),
+                    SC_None, isInline, isConstexpr, SourceLocation(),
+                    TrailingRequiresClause),
       NumCtorInitializers(0), IsInheritingConstructor((bool)Inherited) {
     setImplicit(isImplicitlyDeclared);
     if (Inherited)
@@ -2437,7 +2441,8 @@
          const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
          bool isExplicit, bool isInline, bool isImplicitlyDeclared,
          bool isConstexpr,
-         InheritedConstructor Inherited = InheritedConstructor());
+         InheritedConstructor Inherited = InheritedConstructor(),
+         Expr *TrailingRequiresClause = nullptr);
 
   /// \brief Iterates through the member/base initializer list.
   using init_iterator = CXXCtorInitializer **;
@@ -2629,9 +2634,11 @@
   CXXDestructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
                     const DeclarationNameInfo &NameInfo,
                     QualType T, TypeSourceInfo *TInfo,
-                    bool isInline, bool isImplicitlyDeclared)
+                    bool isInline, bool isImplicitlyDeclared,
+                    Expr *TrailingRequiresClause = nullptr)
     : CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo,
-                    SC_None, isInline, /*isConstexpr=*/false, SourceLocation())
+                    SC_None, isInline, /*isConstexpr=*/false, SourceLocation(),
+                    TrailingRequiresClause)
   {
     setImplicit(isImplicitlyDeclared);
   }
@@ -2644,7 +2651,8 @@
                                    const DeclarationNameInfo &NameInfo,
                                    QualType T, TypeSourceInfo* TInfo,
                                    bool isInline,
-                                   bool isImplicitlyDeclared);
+                                   bool isImplicitlyDeclared,
+                                   Expr *TrailingRequiresClause = nullptr);
   static CXXDestructorDecl *CreateDeserialized(ASTContext & C, unsigned ID);
 
   void setOperatorDelete(FunctionDecl *OD, Expr *ThisArg);
@@ -2684,9 +2692,11 @@
                     const DeclarationNameInfo &NameInfo, QualType T,
                     TypeSourceInfo *TInfo, bool isInline,
                     bool isExplicitSpecified, bool isConstexpr,
-                    SourceLocation EndLocation)
+                    SourceLocation EndLocation,
+                    Expr *TrailingRequiresClause = nullptr)
       : CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
-                      SC_None, isInline, isConstexpr, EndLocation) {
+                      SC_None, isInline, isConstexpr, EndLocation,
+                      TrailingRequiresClause) {
     IsExplicitSpecified = isExplicitSpecified;
   }
 
@@ -2702,7 +2712,8 @@
                                    QualType T, TypeSourceInfo *TInfo,
                                    bool isInline, bool isExplicit,
                                    bool isConstexpr,
-                                   SourceLocation EndLocation);
+                                   SourceLocation EndLocation,
+                                   Expr *TrailingRequiresClause = nullptr);
   static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
 
   /// Whether this function is marked as explicit explicitly.
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -1790,6 +1790,10 @@
   /// the DeclaratorDecl base class.
   DeclarationNameLoc DNLoc;
 
+  /// \brief The constraint-expression introduced by the trailing
+  /// requires-clause provided in the function declaration, if any.
+  Expr *TrailingRequiresClause;
+
   /// \brief Specify that this function declaration is actually a function
   /// template specialization.
   ///
@@ -1830,7 +1834,8 @@
   FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
                const DeclarationNameInfo &NameInfo, QualType T,
                TypeSourceInfo *TInfo, StorageClass S, bool isInlineSpecified,
-               bool isConstexprSpecified)
+               bool isConstexprSpecified,
+               Expr *TrailingRequiresClause = nullptr)
       : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo,
                        StartLoc),
         DeclContext(DK), redeclarable_base(C), SClass(S),
@@ -1842,7 +1847,8 @@
         IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified),
         InstantiationIsPending(false), UsesSEHTry(false), HasSkippedBody(false),
         WillHaveBody(false), IsCopyDeductionCandidate(false),
-        EndRangeLoc(NameInfo.getEndLoc()), DNLoc(NameInfo.getInfo()) {}
+        EndRangeLoc(NameInfo.getEndLoc()), DNLoc(NameInfo.getInfo()),
+        TrailingRequiresClause(TrailingRequiresClause) {}
 
   using redeclarable_base = Redeclarable<FunctionDecl>;
 
@@ -1879,12 +1885,13 @@
                               StorageClass SC,
                               bool isInlineSpecified = false,
                               bool hasWrittenPrototype = true,
-                              bool isConstexprSpecified = false) {
+                              bool isConstexprSpecified = false,
+                              Expr *TrailingRequiresClause = nullptr) {
     DeclarationNameInfo NameInfo(N, NLoc);
     return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo,
                                 SC,
                                 isInlineSpecified, hasWrittenPrototype,
-                                isConstexprSpecified);
+                                isConstexprSpecified, TrailingRequiresClause);
   }
 
   static FunctionDecl *Create(ASTContext &C, DeclContext *DC,
@@ -1894,7 +1901,8 @@
                               StorageClass SC,
                               bool isInlineSpecified,
                               bool hasWrittenPrototype,
-                              bool isConstexprSpecified = false);
+                              bool isConstexprSpecified = false,
+                              Expr *TrailingRequiresClause = nullptr);
 
   static FunctionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
                        
@@ -2148,6 +2156,21 @@
   bool willHaveBody() const { return WillHaveBody; }
   void setWillHaveBody(bool V = true) { WillHaveBody = V; }
 
+  /// \brief Get the constraint-expression introduced by the trailing
+  /// requires-clause in the function/member declaration, or null if no
+  /// requires-clause was provided.
+  Expr *getTrailingRequiresClause() {
+    return TrailingRequiresClause;
+  }
+
+  const Expr *getTrailingRequiresClause() const {
+    return TrailingRequiresClause;
+  }
+
+  void setTrailingRequiresClause(Expr *E) {
+    TrailingRequiresClause = E;
+  }
+
   void setPreviousDeclaration(FunctionDecl * PrevDecl);
 
   FunctionDecl *getCanonicalDecl() override;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to