Page MenuHomePhabricator

Parse concept definition
Needs ReviewPublic

Authored by saar.raz on Nov 22 2017, 9:37 PM.

Details

Diff Detail

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
saar.raz requested changes to this revision.Nov 26 2017, 11:37 AM

Do the requested clang-formatting as shown by hubert, other than that looks good to me :)

This revision now requires changes to proceed.Nov 26 2017, 11:37 AM
changyu updated this revision to Diff 124319.Nov 26 2017, 4:28 PM
changyu edited edge metadata.
  • Fixed indent issues.
  • Moved TODO on boolean atomic constraints to ActOnConceptDefinition where we are currently checking for boolean constraint expression
changyu marked an inline comment as done.Nov 26 2017, 4:29 PM
saar.raz accepted this revision.Nov 26 2017, 11:23 PM
This revision is now accepted and ready to land.Nov 26 2017, 11:23 PM

Thanks for working on this! :)

include/clang/AST/DeclTemplate.h
3043

why not just fix it now?

return SourceRange(getTemplateParameters()->getTemplateLoc(), ConstraintExpr->getLocEnd();

?

include/clang/AST/RecursiveASTVisitor.h
1756

Perhaps something along these lines?

DEF_TRAVERSE_DECL(ConceptDecl, {    

  TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
  
  TRY_TO(TraverseStmt(D->getConstraintExpr()));
  // FIXME: Traverse all the concept specializations (one we implement forming template-ids with them).
})
include/clang/Sema/Sema.h
6407

Have you considered just deferring formation of concept template-ids to the next patch (especially since it might require introduction of another AST node ConceptSpecializationDecl. We could just focus on handling concept declarations/definitions in this one (and emit an unimplemented error if someone tries to form a template-id with a concept within BuildTemplateId etc.) - but perhaps consider making sure we handle name clashes/redeclarations with any other parsed names in the same namespace (within this patch)?

lib/AST/DeclBase.cpp
786

Pls consider just lumping this case with 'Binding/VarTemplate' (which by the way also includes a comment for why we have to add the ugly IDNS_Tag hack here (personally i think we should refactor this functionality, currently it seems split between this and SemaLookup.cpp:getIDNS and would benefit from some sort of well-designed cohesion - but that's another (low-priority) patch)

lib/CodeGen/CGDecl.cpp
110

You would need to add this to EmitTopLevelDecl too to handle global-namespace concept declarations.

lib/Parse/ParseTemplate.cpp
360

I think we should diagnose qualified-name errors here much more gracefully than we do.

i.e. template<class T> concept N::C = ...

  • perhaps try and parse a scope-specifier, and if found emit a diagnostic such as concepts must be defined within their namespace ...
lib/Sema/SemaTemplate.cpp
4137

I don't think we want to just return the constraint expr? I think we would need to create another conceptspecializationDecl node and nest it within a DeclRefExpr? But once again, I think we should defer this to another patch - no?

4179–4185

const bool, no?

7869

Rename L as NameLoc?

7883

Perhaps add a lookup check here? (or a fixme that we are deferring to the next patch), something along these *pseudo-code* lines:

LookupResult Previous(*this, DeclarationNameInfo(DeclarationName(Name),NameLoc), LookupOrdinaryName);
LookupName(Previous, S);
if (Previous.getRepresentativeDecl())    ... if the decl is a concept - give error regarding only one definition allowed in a TU, if a different kind of decl then declared w a different symbol type of error?
7890

Consider refactoring these checks on constraint expressions into a separate function checkConstraintExpression (that we can also call from other contexts such as requires-clauses and nested requires expressions)?

7912

Why not use 'PushOnScopeChains' onto the enclosing scope?
Something along these lines:

assert(S->isTemplateParamScope() && S->getParent() && 
 !S->getParent()->isTemplateParamScope() && "...");
PushOnScopeChains(NewDecl, S->getParent(),/*AddToContext*/true);
test/Parser/cxx-concept-declaration.cpp
0

Name this file starting with cxx2a- please.

faisalv requested changes to this revision.Dec 17 2017, 8:57 AM
faisalv added a reviewer: faisalv.
saar.raz added inline comments.Dec 17 2017, 2:01 PM
lib/Sema/SemaTemplate.cpp
4137

This was meant as a placeholder. The next patch (D41217) replaces this function, I don't think it is that much of a big deal what happens here in this patch.

7890

I did that in the upcoming patches, no need to do it here as well.

faisalv requested changes to this revision.Dec 17 2017, 3:17 PM
faisalv added inline comments.
lib/Sema/SemaTemplate.cpp
4137

This: " I don't think it is that much of a big deal what happens here in this patch." I think is poor practice in an open source project when you're not sure when the next patch will land.

I think, when features are implemented incrementally - each patch should diagnose the yet to be implemented features - and error out as gracefully as possible. So for instance replacing the body of this function with an appropriate diagnostic (that is then removed in future patches) would be the better thing to do here.

7890

Once again - relying on a future patch (especially without a clear FIXME) to tweak the architectural/factorization issues that you have been made aware of (and especially those, such as this, that do not require too much effort), is not practice I would generally encourage.

So changyu, if you agree that these suggestions would improve the quality of the patch and leave clang in a more robust state (maintenance-wise or execution-wise), then please make the changes. If not, please share your thoughts as to why these suggestions would either not be an improvement or be inconsistent with the theme of this patch.

Thanks!

This revision now requires changes to proceed.Dec 17 2017, 3:17 PM
changyu marked 6 inline comments as done.Dec 20 2017, 11:59 PM
changyu added inline comments.
lib/Sema/SemaTemplate.cpp
7912

The condition

S->isTemplateParamScope()

fails in this case

template<concept T> concept D1 = true; // expected-error {{expected template parameter}}

ParseTemplateDeclarationOrSpecialization calls ParseTemplateParameters which eventually calls ParseNonTypeTemplateParameter. ParseNonTypeTemplateParameter prints the diag and fails but does not cause ParseTemplateParameters to fail (I'm not sure why). ParseTemplateDeclarationOrSpecialization proceeds to parse the concept definition, and we get this

/home/changyu/test.cpp:1:10: error: expected template parameter
template<concept T> concept D1 = true; // expected-error {{expected template parameter}}
         ^
clang: /home/changyu/git/llvm/tools/clang/lib/Sema/SemaTemplate.cpp:7747: clang::Decl* clang::Sema::ActOnConceptDefinition(clang::Scope*, clang::MultiTemplateParamsArg, clang::IdentifierInfo*, clang::SourceLocation, clang::Expr*): Assertion `S->isTemplateParamScope() && "Not in template param scope?"' failed.

What should we do?

faisalv added inline comments.Dec 23 2017, 9:10 AM
lib/Sema/SemaTemplate.cpp
7912

I think this occurs because our template parameter list is incorrectly perceived as empty - i.e. once the error occurs - to continue processing errors clang assumes this case is an explicit-specialization and replaces the template parameter scope with the outer scope. I think the thing to do here - which might also address the case where folks actually write 'template<> concept' is to actually check if template-parameter-list is empty - and emit a diagnostic about concepts can not be explicit specializations or some such ...

On a somewhat related note - i think the logic for signaling, handling and propagating failures of parsing the template parameter list might be a little broken (fixing which, might avoid triggering the assertion in template<concept> but not template<>). I might submit a patch to fix that error handling-issue separately - but either way I think we should handle the explicit-specialization error?

Thoughts?

changyu marked 27 inline comments as done.Dec 23 2017, 8:48 PM
changyu added inline comments.
lib/Sema/SemaTemplate.cpp
7890

I removed it here since Saar fixed it in his patch.

changyu updated this revision to Diff 128094.Dec 23 2017, 8:48 PM
changyu marked an inline comment as done.

I think this looks good enough to commit - do you have commit privileges - or do you need one of us to commit it for you?
thank you!

I don't have commit privilege. And also there's one more problem we might want to address first.

Thank you.

lib/Parse/ParseTemplate.cpp
180

There's one problem here.

​I added this if in attempt to catch the following case (but it's wrong)

	​template<> concept D1 = true;  // expected-error {{expected template parameter}}

The problem is I'm not sure how to differentiate between the above situation and the following

	​template<concept T> concept D1 = true; // expected-error {{expected template parameter}}

Both have an empty template parameter list​. The latter case has diagnostic printed by ParseNonTypeTemplateParameter while the former has not (so we try to catch it here).

What should we do?

faisalv added inline comments.Dec 24 2017, 11:23 AM
lib/Parse/ParseTemplate.cpp
180

I was thinking that we would just emit a (redundant in the case of a bad template parameter) message in Sema if the template-parameters are empty that explicit specializations are not allowed here. while it would be a little misleading in the invalid template parameter case - to fix this robustly would require some fine-tuning and correcting some of the handshaking/error-propagation between the parsing of the template parameters and the code that calls it, I think. I would vote for not holding up this patch for that, unless you feel strongly you'd like to fix that behavior - then we can try and work on that first?

Thoughts?

changyu updated this revision to Diff 128123.Dec 24 2017, 8:43 PM
changyu marked 2 inline comments as done.

I moved some template param checks from Parser::ParseTemplateDeclarationOrSpecialization to Parser::ParseConceptDefinition and Sema::ActOnConceptDefinition.

lib/Parse/ParseTemplate.cpp
180

Sure, let's fix that in another patch. I added a note for this in cxx2a-concept-declaration.cpp.

saar.raz added inline comments.Mar 10 2018, 3:55 AM
lib/Parse/ParseTemplate.cpp
160–163

Perhaps add a LangOpts.ConceptsTS check here?

saar.raz added inline comments.Mar 10 2018, 6:01 AM
lib/Parse/ParseTemplate.cpp
376

We could accept 'bool' here to be nice to people coming in from the old Concepts TS version of these decls - and emit a proper warning.

I discussed this briefly w Hubert - and i'm planning on modifying this patch slightly so that it flows through ParseDeclSpecifier and handles attributes and other invalid decl-specifiers such as static etc. more gracefully on a concept decl. I have this partially implemented - my hope is to get this done v soonish so feel free to ping me if you don't hear anything about this in a week or so ...

rsmith added inline comments.Aug 6 2018, 4:18 PM
include/clang/AST/DeclTemplate.h
3015

This comment isn't appropriate. Please just describe what the node is. (And note that a definition is a kind of declaration, despite common parlance.)

3035

Please remove this again. ASTDeclReader should set the ConstraintExpr field directly. The AST is intended to be immutable after creation, so should generally not have setters.

3043

There's a bigger problem here:

TemplateDecl *TD = /*some ConceptDecl*/;
auto SR = TD->getSourceRange(); // crash

TemplateDecl has a hard assumption that it contains a TemplatedDecl. So, three options:

  1. Change TemplateDecl and all its users to remove this assumption (hard and leads to an awkward-to-use AST)
  2. Add a Decl subclass that acts as the templated declaration in a concept declaration (corresponding to the C++ grammar's concept-definition production)
  3. Make ConceptDecl not derive from a TemplateDecl at all

I think option 2 is my preference, but option 3 is also somewhat appealing (there are other ways in which a concept is not a template: for instance, it cannot be constrained, and it cannot be classified as either a type template or a non-type template, because its kind depends on the context in which it appears).

Of course, this leads to one of the Hard Problems Of Computer Science: naming things. ConceptDecl for a concept-definition and ConceptTemplateDecl for the template-head concept-definition would be consistent with the rest of the AST. It's a little unfortunate for the longer name to be the AST node that we actually interact with, but the consistency is probably worth the cost.

include/clang/AST/RecursiveASTVisitor.h
1759

Hmm, concepts don't really have specializations, though, do they? (Much like alias templates.) And because they're substituted incrementally, and the result of evaluation can vary at different points in the same translation unit, it's not obvious how much we can actually cache.

I suppose I'll see this was handled in later patches in the series :)

include/clang/Basic/DiagnosticParseKinds.td
1225

I would expect something more general here. For an alias-declaration, we say:

"error: name defined in alias declaration must be an identifier"

This is then also appropriate for other kinds of invalid concept-names such as

template<typename T> concept operator int = true;
include/clang/Basic/DiagnosticSemaKinds.td
2437–2438

"must be 'bool'" doesn't make sense. Maybe "constraint expression must be of type 'bool' but is of type %0" or similar?

2441–2442

Do not use "may not" in this context; it's ambiguous (this could be read as "I'm not sure if this concept has associated constraints"). Use "cannot" instead.

(And generally prefer "can" over "may" or "must" in diagnostics.)

2443–2444

Please make this a bit less informal and a little more informative. Perhaps "sorry, unimplemented concepts feature used". For a temporary "under construction" error, it's also OK to include a %0 and pass in a string describing the feature if you like.

2445–2446

maybe not -> cannot

include/clang/Basic/TemplateKinds.h
19

Note this comment. You need to track down the diagnostics that use this enum and update their %selects to cover the new name kind.

lib/AST/DeclBase.cpp
731–734

This comment just repeats what the comment before it already says: please remove it again.

lib/Parse/ParseTemplate.cpp
160–163

No need. If you see a kw_concept keyword, you have the language feature enabled.

376–379

Please also check for a < after the identifier, and diagnose the attempt to form a concept partial / explicit specialization. (I'm fine with leaving that to a later patch if you prefer.)

One option would be to call ParseUnqualifiedId and then diagnose anything that's not a simple identifier. (See ParseAliasDeclarationAfterDeclarator for how we do this for alias declarations.)

385

Use tok::equal here, not a string literal.

392

This diagnostic doesn't take an argument.

lib/Sema/SemaTemplate.cpp
4179–4186

This needs rebasing onto SVN trunk. (We have lambda'fied the dependent arguments check there.)

7887

You need to check CurContext->getRedeclContext(). A concept can be defined in a LinkageSpecDecl (with C++ linkage) or an ExportDecl, for instance.

7911–7912

ConceptDecl::Create cannot return null. Checking this doesn't make sense, because (a) this is dead code, and (b) if this happened, you would return null without issuing a diagnostic.

saar.raz added inline comments.Tue, Apr 9, 1:32 PM
include/clang/AST/DeclTemplate.h
3043

The dummy decl is pretty confusing and will be a very weird decl in and of itself. I can't think of a good name right now, but your proposed naming will be pretty confusing given that a ConceptTemplateDecl does not template a concept declaration given the meaning of the phrase in the standard... Maybe ConceptBodyDecl? ConceptDummyDecl? ConceptDefinitionDecl? We need something that screams "this is not interesting" for the AST usage to be reasonable.
Option 3 feels like loads of code duplication.
I'm not entirely sure how many blind (through TemplateDecl) uses of getTemplatedDecl there are, but there might not be that many, in which case the first option might be the lesser of all these evils.

saar.raz updated this revision to Diff 194417.Tue, Apr 9, 4:24 PM

Address most of rsmith's CR comments, rebase onto trunk

Herald added a project: Restricted Project. · View Herald TranscriptTue, Apr 9, 4:24 PM
Herald added a subscriber: jfb. · View Herald Transcript
saar.raz commandeered this revision.Tue, Apr 9, 4:28 PM
saar.raz edited reviewers, added: changyu; removed: saar.raz.
saar.raz marked 21 inline comments as done.Tue, Apr 9, 4:33 PM

Only the TemplatedDecl issue remains, all other comments have been addressed and we're rebased onto master.
@rsmith please reply to the last comment, and lets finally start merging these :)

Thanks!

Please revert the (presumably unintended) mode changes to the ptxas executables.

include/clang/AST/DeclTemplate.h
3016

This should also derive from Mergeable<ConceptDecl>, since we are permitted to merge multiple definitions of the same concept across translation units by C++20 [basic.def.odr]/12.

3043

Faisal's comment is marked "Done" but not done.

ConceptBodyDecl or something like it seems reasonable. But I think we can consider that after landing this patch, and leave the templated declaration null for now.

include/clang/Basic/DiagnosticParseKinds.td
1260–1270

Generally we don't leave blank lines between diagnostic definitions, and instead use the continuation indent to visually separate them.

1261–1263

The phrasing of this (particularly the "if any") is a little confusing. I think it's fine to just use the err_concept_definition_not_identifier diagnostic for this case.

1269

I'd probably phrase this as

"ISO C++2a does not permit the 'bool' keyword after 'concept'"

(The Concepts TS isn't really the past -- TSes are more like an alternative reality -- so "no longer" is a bit odd.) I'd also be tempted to turn this into an ExtWarn so that we can accept code targeting the Concepts TS with a warning.

include/clang/Basic/DiagnosticSemaKinds.td
2443

Drop the ", did you attempt this?". It doesn't add anything to the diagnostic, and might be read as a little snarky, frustrating the user.

lib/AST/ASTDumper.cpp
182–186

This needs rebasing; I believe the right place for this is now split between TextNodeDumper.cpp and ASTNodeTraverser.h.

lib/AST/DeclPrinter.cpp
1084–1085

This looks wrong: we'll only print the template parameters, and not the concept <name> = <expr>; part. Please add another else if for the ConceptDecl case (or similar).

lib/Index/IndexDecl.cpp
658–662

This change looks redundant. Note that VisitTemplateDecl below already returned true if getTemplatedDecl() is null.

lib/Parse/ParseTemplate.cpp
58

There's no 'export'[opt] in template-head.

387

Consider calling DiagnoseAndSkipCXX11Attributes before and after parsing the name of the concept; it seems likely that people will try adding attributes there, and we should give a good diagnostic for this until they start being permitted in one of those two locations.

lib/Sema/SemaTemplate.cpp
7928

This should be PushOnScopeChains(NewDecl, S); instead (though I think in practice it won't matter until/unless we start supporting block-scope concept definitions).

lib/Sema/SemaTemplateInstantiateDecl.cpp
3365

No need for a return here; the code after an llvm_unreachable is unreachable =)

lib/Serialization/ASTReaderDecl.cpp
2082

Call mergeMergeable(D) at the end of this.