forked from OSchip/llvm-project
[Concepts] Parsing of requires-clause in template-declaration
Summary: This change implements parse-only acceptance of the optional requires-clause in a template-declaration. Diagnostic testing is added for cases where the grammar is ambiguous with the expectation that the longest token sequence which matches the syntax of a constraint-expression is consumed without backtracking. Reviewers: faisalv, fraggamuffin, rsmith Reviewed By: rsmith Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D10462 llvm-svn: 240611
This commit is contained in:
parent
6a75acb1c2
commit
ec3cb573f5
|
@ -1331,6 +1331,7 @@ public:
|
|||
|
||||
ExprResult ParseExpression(TypeCastState isTypeCast = NotTypeCast);
|
||||
ExprResult ParseConstantExpression(TypeCastState isTypeCast = NotTypeCast);
|
||||
ExprResult ParseConstraintExpression();
|
||||
// Expr that doesn't include commas.
|
||||
ExprResult ParseAssignmentExpression(TypeCastState isTypeCast = NotTypeCast);
|
||||
|
||||
|
|
|
@ -205,6 +205,24 @@ ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) {
|
|||
return Actions.ActOnConstantExpression(Res);
|
||||
}
|
||||
|
||||
/// \brief Parse a constraint-expression.
|
||||
///
|
||||
/// \verbatim
|
||||
/// constraint-expression: [Concepts TS temp.constr.decl p1]
|
||||
/// logical-or-expression
|
||||
/// \endverbatim
|
||||
ExprResult Parser::ParseConstraintExpression() {
|
||||
// FIXME: this may erroneously consume a function-body as the braced
|
||||
// initializer list of a compound literal
|
||||
//
|
||||
// FIXME: this may erroneously consume a parenthesized rvalue reference
|
||||
// declarator as a parenthesized address-of-label expression
|
||||
ExprResult LHS(ParseCastExpression(/*isUnaryExpression=*/false));
|
||||
ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr));
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
bool Parser::isNotExpressionStart() {
|
||||
tok::TokenKind K = Tok.getKind();
|
||||
if (K == tok::l_brace || K == tok::r_brace ||
|
||||
|
|
|
@ -116,7 +116,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
|
|||
SmallVector<Decl*, 4> TemplateParams;
|
||||
if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(),
|
||||
TemplateParams, LAngleLoc, RAngleLoc)) {
|
||||
// Skip until the semi-colon or a }.
|
||||
// Skip until the semi-colon or a '}'.
|
||||
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
|
||||
TryConsumeToken(tok::semi);
|
||||
return nullptr;
|
||||
|
@ -132,6 +132,17 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
|
|||
if (!TemplateParams.empty()) {
|
||||
isSpecialization = false;
|
||||
++CurTemplateDepthTracker;
|
||||
|
||||
if (TryConsumeToken(tok::kw_requires)) {
|
||||
ExprResult ER =
|
||||
Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression());
|
||||
if (!ER.isUsable()) {
|
||||
// Skip until the semi-colon or a '}'.
|
||||
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
|
||||
TryConsumeToken(tok::semi);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LastParamListWasEmpty = true;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ %s -verify
|
||||
|
||||
// Test parsing of constraint-expressions in cases where the grammar is
|
||||
// ambiguous with the expectation that the longest token sequence which matches
|
||||
// the syntax is consumed without backtracking.
|
||||
|
||||
// type-specifier-seq in conversion-type-id
|
||||
template <typename T> requires (bool)&T::operator short
|
||||
unsigned int foo(); // expected-error {{C++ requires a type specifier for all declarations}}
|
||||
|
||||
// type-specifier-seq in new-type-id
|
||||
template <typename T> requires (bool)sizeof new (T::f()) short
|
||||
unsigned int bar(); // expected-error {{C++ requires a type specifier for all declarations}}
|
||||
|
||||
template<typename T> requires (bool)sizeof new (T::f()) unsigned // expected-error {{'struct' cannot be signed or unsigned}}
|
||||
struct X { }; // expected-error {{'X' cannot be defined in a type specifier}}
|
||||
|
||||
// C-style cast
|
||||
// of function call on function-style cast
|
||||
template <typename T> requires (bool(T()))
|
||||
T (*fp)(); // expected-error {{use of undeclared identifier 'fp'}}
|
||||
|
||||
// function-style cast
|
||||
// as the callee in a function call
|
||||
struct A {
|
||||
static int t;
|
||||
template <typename T> requires bool(T())
|
||||
(A(T (&t))) { } // expected-error {{called object type 'bool' is not a function or function pointer}}
|
||||
};
|
|
@ -0,0 +1,82 @@
|
|||
// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ %s -verify
|
||||
// expected-no-diagnostics
|
||||
|
||||
// Test parsing of the optional requires-clause in a template-declaration.
|
||||
|
||||
template <typename T> requires true
|
||||
void foo() { }
|
||||
|
||||
|
||||
template <typename T> requires !0
|
||||
struct A {
|
||||
void foo();
|
||||
struct AA;
|
||||
enum E : int;
|
||||
static int x;
|
||||
|
||||
template <typename> requires true
|
||||
void Mfoo();
|
||||
|
||||
template <typename> requires true
|
||||
struct M;
|
||||
|
||||
template <typename> requires true
|
||||
static int Mx;
|
||||
|
||||
template <typename TT> requires true
|
||||
using MQ = M<TT>;
|
||||
};
|
||||
|
||||
template <typename T> requires !0
|
||||
void A<T>::foo() { }
|
||||
|
||||
template <typename T> requires !0
|
||||
struct A<T>::AA { };
|
||||
|
||||
template <typename T> requires !0
|
||||
enum A<T>::E : int { E0 };
|
||||
|
||||
template <typename T> requires !0
|
||||
int A<T>::x = 0;
|
||||
|
||||
template <typename T> requires !0
|
||||
template <typename> requires true
|
||||
void A<T>::Mfoo() { }
|
||||
|
||||
template <typename T> requires !0
|
||||
template <typename> requires true
|
||||
struct A<T>::M { };
|
||||
|
||||
template <typename T> requires !0
|
||||
template <typename> requires true
|
||||
int A<T>::Mx = 0;
|
||||
|
||||
|
||||
template <typename T> requires true
|
||||
int x = 0;
|
||||
|
||||
template <typename T> requires true
|
||||
using Q = A<T>;
|
||||
|
||||
struct C {
|
||||
template <typename> requires true
|
||||
void Mfoo();
|
||||
|
||||
template <typename> requires true
|
||||
struct M;
|
||||
|
||||
template <typename> requires true
|
||||
static int Mx;
|
||||
|
||||
template <typename T> requires true
|
||||
using MQ = M<T>;
|
||||
};
|
||||
|
||||
template <typename> requires true
|
||||
void C::Mfoo() { }
|
||||
|
||||
template <typename> requires true
|
||||
struct C::M { };
|
||||
|
||||
template <typename> requires true
|
||||
int C::Mx = 0;
|
Loading…
Reference in New Issue