[PATCH] D53847: [C++2a] P0634r3: Down with typename!
Richard Smith - zygoloid via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 12 17:31:39 PST 2018
rsmith added a comment.
Thank you, this is looking really good.
================
Comment at: include/clang/Parse/Parser.h:2054
+ case DeclSpecContext::DSC_template_param:
+ case DeclSpecContext::DSC_template_type_arg:
+ case DeclSpecContext::DSC_normal:
----------------
Rakete1111 wrote:
> rsmith wrote:
> > This doesn't seem right to me. Doesn't this mean that `X<T::U>` will change from being a non-type template argument to being a type template argument?
> >
> > Maybe that's a bug in the wording paper, though, since that context *is* a /type-id/.
> AFAIK no it won't, but I can't really tell if that's the right behavior or not. This patch doesn't touch the `X<T::U>` case.
I don't think I agree. `ParseTemplateArgument`, after disambiguation, parses a type name in `TemplateArgContext`, which results in a `DeclSpecContext` of `DSC_template_type_arg`, which means that we treat the context as an implicit typename context.
It looks to me like that will cause us to accept implicit `typename` in cases that we can disambiguate as being type template arguments, which would be wrong. For example, it looks like `X<const T::U>` would be incorrectly accepted: `typename` is required here because this type-id is not an implicit typename context.
Perhaps the right way to fix this would be to change `Parser::getDeclSpecContextFromDeclaratorContext` to map `TemplateArgContext` to a different kind of `DeclSpecContext` than `TemplateTypeArgContext` so that we can tell the difference here.
================
Comment at: lib/Parse/ParseDecl.cpp:6433
- ParseDeclarationSpecifiers(DS);
+ bool AllowImplicitTypename;
+ if (D.getContext() == DeclaratorContext::MemberContext ||
----------------
We should determine this up-front rather than computing it once per parameter that we parse.
================
Comment at: lib/Parse/ParseDecl.cpp:6439
+ AllowImplicitTypename =
+ D.getCXXScopeSpec().isSet() && Actions.isDeclaratorFunctionLike(D);
----------------
I don't think you need to do name lookup here. I think you can use `D.isFunctionDeclaratorAFunctionDeclaration()` instead of `isDeclaratorFunctionLike(D)` -- because we've already committed to parsing this as a function declaration in that case, a qualified function name will either redeclare something from its context (in which case implicit typename is permitted) or be ill-formed.
================
Comment at: lib/Parse/Parser.cpp:1518
+ if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(
+ SS, !WasScopeAnnotation, /*AllowImplicitTypename=*/true))
return ANK_Error;
----------------
What justifies allowing implicit typename here? Don't we need the caller to tell us if that's OK?
... actually, perhaps this tentatively-declared identifiers logic should only be performed if `SS.isEmpty()` (because a tentatively-declared identifier can never be found within a scope named by a nested-name-specifier), at which point the value of this flag doesn't matter.
================
Comment at: lib/Parse/Parser.cpp:1783
+ AllowImplicitTypename &&
+ getCurScope()->isFunctionPrototypeScope())) {
SourceLocation BeginLoc = Tok.getLocation();
----------------
Do we need this scope check? (It would seem preferable to trust the caller to have passed in the right flag value, if we can.)
================
Comment at: lib/Sema/Sema.cpp:2006-2019
+bool Sema::isDeclaratorFunctionLike(const Declarator &D) {
+ assert(D.getCXXScopeSpec().isSet() &&
+ "can only be called for qualified names");
+ LookupResult LR(*this, D.getIdentifier(), D.getBeginLoc(), LookupOrdinaryName,
+ ForVisibleRedeclaration);
+ DeclContext *DC = computeDeclContext(D.getCXXScopeSpec());
+ if (!DC)
----------------
Some thoughts on this:
* Can this be unified with the lookup code in `HandleDeclarator`? This is really the same lookup, repeated in two places.
* It'd be nice to cache this lookup, rather than performing it three times (once when disambiguating a parenthesized initializer from a function declaration, once when we're about to parse a parameter-declaration-clause, and once in `HandleDeclarator` after parsing completes -- though at least that's reduced to two lookups if you make the change I suggested in `ParseParameterDeclarationClause`)
* If we don't do the caching, what happens if lookup fails due to ambiguity? Do we get the same error multiple times (once for each time we perform the lookup)?
================
Comment at: lib/Sema/Sema.cpp:2010
+ LookupResult LR(*this, D.getIdentifier(), D.getBeginLoc(), LookupOrdinaryName,
+ ForVisibleRedeclaration);
+ DeclContext *DC = computeDeclContext(D.getCXXScopeSpec());
----------------
Should this be `forRedeclarationInCurContext()`?
================
Comment at: lib/Sema/Sema.cpp:2011
+ ForVisibleRedeclaration);
+ DeclContext *DC = computeDeclContext(D.getCXXScopeSpec());
+ if (!DC)
----------------
`EnteringContext` should presumably be `true` here, so that we can look into class templates.
================
Comment at: lib/Sema/Sema.cpp:2016
+ LookupQualifiedName(LR, DC);
+ return std::all_of(LR.begin(), LR.end(), [](Decl *Dcl) {
+ return isa<FunctionDecl>(Dcl) || isa<FunctionTemplateDecl>(Dcl);
----------------
`UsingDecl`s in this set should not disqualify us from the "function-like" interpretation.
================
Comment at: lib/Sema/Sema.cpp:2017
+ return std::all_of(LR.begin(), LR.end(), [](Decl *Dcl) {
+ return isa<FunctionDecl>(Dcl) || isa<FunctionTemplateDecl>(Dcl);
+ });
----------------
I think you need to `getUnderlyingDecl` of `Dcl` here; lookup might find `UsingShadowDecl`s that you need to look through.
================
Comment at: test/SemaCXX/unknown-type-name.cpp:121-122
template<typename T>
-A<T>::g() { } // expected-error{{requires a type specifier}}
+A<T>::g() { } // expected-error{{expected unqualified-id}}
+// expected-warning at -1{{implicit 'typename' is a C++2a extension}}
----------------
Rakete1111 wrote:
> rsmith wrote:
> > rsmith wrote:
> > > This is a diagnostic quality regression. Perhaps that's an inevitable consequence of P0634, but we should at least try to do better.
> > This is marked "done" but doesn't seem to be done?
> Oops, don't know why I did that. I can't figure out a way to fix this. I can implement a basic heuristic to detect some very basic cases like this one, but I don't think it's worth it.
OK, fair enough. This one does seem hard to diagnose well.
Repository:
rC Clang
https://reviews.llvm.org/D53847
More information about the cfe-commits
mailing list