This is an archive of the discontinued LLVM Phabricator instance.

[PATCH] [CONCEPTS] Parsing of concept keyword
ClosedPublic

Authored by nwilson on Jun 17 2015, 9:27 PM.

Details

Summary

This change adds parsing for the concept keyword in a declaration and tracks the location. Diagnostic testing added for invalid use of concept keyword.

Diff Detail

Event Timeline

nwilson updated this revision to Diff 27910.Jun 17 2015, 9:27 PM
nwilson retitled this revision from to [PATCH] [CONCEPTS] Parsing of concept keyword.
nwilson updated this object.
nwilson edited the test plan for this revision. (Show Details)
nwilson added a subscriber: Unknown Object (MLST).

Some issues with the test case; minor issues otherwise.

I would suggest testing the following as well:

template <typename T>
struct A { typedef bool Boolean; };

template <int N>
A<void>::Boolean concept C3(!0);

template <typename T, int = 0>
concept auto C4(void) -> bool { return true; }

constexpr int One = 1;

template <typename>
static concept decltype(!0) C5{ bool(One) };
lib/Parse/ParseDecl.cpp
4437

I'm not sure what C++TS1 is meant to refer to since the Concepts TS is not TS1.

test/Parser/cxx-concepts-value-function.cpp
1 ↗(On Diff #27910)

I am not familiar with the 0|1 syntax being used here; my local copy of "lit" interprets it as a pipe to a command "1". Perhaps this should be two run lines?

4 ↗(On Diff #27910)

The usual way to express this is "function concepts and variable concepts".

11 ↗(On Diff #27910)

-DDIAG=0 would still trigger the #ifdef DIAG here (which explains why the test file might pass with expected-no-diagnostics).

test/Parser/cxx-concepts-value-function.cpp
11 ↗(On Diff #27910)

I meant without expected-no-diagnostics somewhere.

nwilson added inline comments.Jun 18 2015, 6:58 AM
lib/Parse/ParseDecl.cpp
4437

I'll fix that. Any preference on a comment? C++14 Concepts-ts?

test/Parser/cxx-concepts-value-function.cpp
1 ↗(On Diff #27910)

Yeah, I was trying to keep it on one line. I'll change it to two.

4 ↗(On Diff #27910)

Thanks. I'll make the change for the correct verbiage.

11 ↗(On Diff #27910)

Hmm, yeah, I missed that and thought it was working. Is there a better way to use/suppress the diagnostic cases?

lib/Parse/ParseDecl.cpp
4437
// C++ Concepts TS - concept

would work.

test/Parser/cxx-concepts-value-function.cpp
11 ↗(On Diff #27910)

#if DIAG instead of #ifdef would work. I guess expected-no-diagnostics could be in the #else for that.

rsmith added inline comments.Jun 18 2015, 1:14 PM
lib/Sema/DeclSpec.cpp
899

Why just a warning? [dcl.spec]/2 seems to apply to concept just like any other decl-specifier.

test/Parser/cxx-concepts-value-function.cpp
3–4 ↗(On Diff #27910)

We typically use BCPL //-comments in our C++ testcases, with no line-of-*s.

11 ↗(On Diff #27910)

Just run the test once, and remove the #ifdef.

15 ↗(On Diff #27910)

Which of the various errors on this line are you trying to test here?

nwilson added inline comments.Jun 18 2015, 1:50 PM
lib/Sema/DeclSpec.cpp
899

Wouldn't this be similar to constexpr (above)? Do you think it should error out?

test/Parser/cxx-concepts-value-function.cpp
3–4 ↗(On Diff #27910)

Okay. I'll make the fix.

11 ↗(On Diff #27910)

I'll submit a patch for this shortly so you guys can see if this explanation doesn't make sense. But, how about if I use the directives likes this:

#if DIAG == 0
RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s -DDIAG=0
expected-no-diagnostics

  • test cases ***

#elif DIAG == 1
// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s -DDIAG=1

  • test cases ***

#endif

15 ↗(On Diff #27910)

All of those diagnostics are generated, so I guess all of them.

Is there a better way to do it? Should I only handle one?

rsmith added inline comments.Jun 18 2015, 2:04 PM
lib/Sema/DeclSpec.cpp
899

Yes, it should. (We don't yet implement DR1830 so the pre-existing cases aren't caught yet.)

test/Parser/cxx-concepts-value-function.cpp
11 ↗(On Diff #27910)

What are you trying to achieve by running the test twice?

15 ↗(On Diff #27910)

It'd be clearer to have a separate declaration for each different case you're trying to test, so that someone who causes the test to fail (say, by changing the parser's error recovery) can understand whether they've actually broken something.

test/Parser/cxx-concepts-value-function.cpp
11 ↗(On Diff #27910)

The presence of errors in a file may prevent further processing. Such further processing is not guaranteed to apply only to code which occurs lexically after the location of the error. By avoiding diagnostic cases in one of the runs, we can be more confident that the cases which should not receive diagnostics would not do so (instead of merely having the unexpected diagnostics conveniently preempted).

rsmith added inline comments.Jun 18 2015, 5:53 PM
test/Parser/cxx-concepts-value-function.cpp
11 ↗(On Diff #27910)

Failure to recover properly from an error would be a bug -- the parse of later unrelated code should not be affected by an earlier failure, except in extreme cases. The same argument would also imply that we should not have two "expected to fail" tests in a row in one test file, because the earlier failure could conceivably prevent the later failure from happening (or the later failure might only happen when the earlier failure does).

The valid cases will be tested more thoroughly in higher layers (for instance, testing that semantic analysis can use a concept to select an overload and that IR generation can generate correct IR for use of a concept), so I'm not at all worried about those later tests failing to catch a bug where a trivial concept definition leads to an unexpected error.

As a more general observation: there is an established pattern for these kinds of test (and many other things) in Clang. If our established pattern is wrong, we should deal with that by discussing the pattern and how to fix it, then fixing it globally, not by deviating from that pattern in an individual change (that will lead to a fragmented and harder-to-maintain codebase).

test/Parser/cxx-concepts-value-function.cpp
11 ↗(On Diff #27910)

Okay; thanks for the explanation.

nwilson updated this revision to Diff 27993.Jun 18 2015, 8:10 PM
nwilson edited edge metadata.

This is an update for the comments in the review: make the // comments clearer/correct when referring to C++ concepts (values and functions), use warning diagnostic for duplicate declaration extension and add associated test cases, added more test cases, and removed the diagnostic directives.

nwilson added inline comments.Jun 18 2015, 8:16 PM
test/Parser/cxx-concepts-value-function.cpp
30 ↗(On Diff #27993)

Is there a better way to list multiple diagnostics that would occur from the same declaration? When separating out each declaration for each test case such as:

template< concept T > concept bool D2 { return true; } expected-error {{unknown type name 'T'}}
template< concept T > concept bool D3 { return true; }
expected-error {{expected expression}}
template< concept T > concept bool D4 { return true; } // expected-error {{expected ';' at end of declaration}}

clang complains:
'error' diagnostics seen but not expected:

and lists all of the diagnostics.

lib/Sema/DeclSpec.cpp
899

This is still just a warning without -pedantic-errors; I'm okay with it if Richard is.

rsmith added inline comments.Jun 18 2015, 8:26 PM
test/Parser/cxx-concepts-value-function.cpp
1 ↗(On Diff #27993)

The name of this test file could be better. Something like 'cxx-concept-declaration.cpp', maybe, if you're intending on putting tests for the other parsing changes (requires-clauses, requires-expressions, concept-introducer syntax, ...) into separate files?

30 ↗(On Diff #27993)

Try changing your test so each case only fails in one way. Like:

template< concept T > concept bool D2 = true; // expected-error {{unknown type name 'T'}}
template< typename T > concept bool D3 { return true; }; // expected-error {{expected expression}}
template< typename T > concept bool D4 { true } // expected-error {{expected ';' at end of declaration}}

... though the second and third cases are really testing variable/function disambiguation and don't have anything to do with concepts, so I'm not sure they belong here at all.

rsmith added inline comments.Jun 18 2015, 8:28 PM
lib/Sema/DeclSpec.cpp
899

This is consistent with how we treat other violations of the same rule; it seems fine to me.

test/Parser/cxx-concepts-value-function.cpp
1 ↗(On Diff #27993)

There is a patch for requires-clauses here in case we want to coordinate the filenames: http://reviews.llvm.org/D10462.

nwilson added inline comments.Jun 18 2015, 8:45 PM
test/Parser/cxx-concepts-value-function.cpp
1 ↗(On Diff #27993)

Yeah, I wasn't sure about the file name. I'd be okay with cxx-concept-declaration.cpp.

Hubert - do you have any preference?

30 ↗(On Diff #27993)

Ahh, yeah, that makes sense. Thanks. I'll take the last two out in that case, and add more when adding actual diagnostics for ill formed concept declarations.

test/Parser/cxx-concepts-value-function.cpp
1 ↗(On Diff #27993)

Sounds good.

nwilson updated this revision to Diff 28002.Jun 18 2015, 9:08 PM
  • Renaming test file name to cxx-concept-declaration.cpp
  • Removing tests D2 and D3 as they're not applicable
rsmith accepted this revision.Jun 29 2015, 6:05 PM
rsmith edited edge metadata.

LGTM

This revision is now accepted and ready to land.Jun 29 2015, 6:05 PM
hubert.reinterpretcast edited edge metadata.