Skip to content

Commit

Permalink
[Concepts] Parsing of requires-clause in template-declaration
Browse files Browse the repository at this point in the history
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
  • Loading branch information
hubert-reinterpretcast committed Jun 25, 2015
1 parent 6a75acb commit ec3cb57
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 1 deletion.
1 change: 1 addition & 0 deletions clang/include/clang/Parse/Parser.h
Expand Up @@ -1331,6 +1331,7 @@ class Parser : public CodeCompletionHandler {

ExprResult ParseExpression(TypeCastState isTypeCast = NotTypeCast);
ExprResult ParseConstantExpression(TypeCastState isTypeCast = NotTypeCast);
ExprResult ParseConstraintExpression();
// Expr that doesn't include commas.
ExprResult ParseAssignmentExpression(TypeCastState isTypeCast = NotTypeCast);

Expand Down
18 changes: 18 additions & 0 deletions clang/lib/Parse/ParseExpr.cpp
Expand Up @@ -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 ||
Expand Down
13 changes: 12 additions & 1 deletion clang/lib/Parse/ParseTemplate.cpp
Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down
29 changes: 29 additions & 0 deletions clang/test/Parser/cxx-concepts-ambig-constraint-expr.cpp
@@ -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}}
};
82 changes: 82 additions & 0 deletions clang/test/Parser/cxx-concepts-requires-clause.cpp
@@ -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;

0 comments on commit ec3cb57

Please sign in to comment.