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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits