[PATCH] D90188: Add support for attribute 'using_if_exists'
Richard Smith - zygoloid via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 27 15:33:37 PDT 2020
rsmith added a comment.
In addition to moving the diagnostic to `DiagnoseUseOfDecl`, you may well get better error recovery if you teach `ClassifyName` about the new kind of declaration, and have it `DiagnoseUseOfDecl` it immediately and return `NameClassification::Error()` -- that way, the parser knows it can't use the kind of the name to disambiguate the parse and should use heuristics to figure out whether a type or non-type was intended instead.
================
Comment at: clang/lib/AST/DeclBase.cpp:816
+ case UnresolvedUsingIfExists:
+ return IDNS_Type | IDNS_Member | IDNS_Ordinary;
+
----------------
Hmm. This is tricky: `IDNS_Type` isn't necessarily appropriate, but we don't know one way or the other. Consider:
```
namespace N {
using ::stat [[clang::using_if_exists]];
struct stat;
}
```
Should we accept or reject? If the intent is that the using-declaration brings in only a non-type name, then this should be valid, but if it's intended to also bring in a type, then we'd have a conflict.
I suppose on balance being more restrictive (including `IDNS_Type` here) is probably better.
You don't need `IDNS_Member` here; that's only different from `IDNS_Ordinary` in C.
================
Comment at: clang/lib/Sema/SemaDecl.cpp:438-439
+ NamedDecl *RealRes = *Res;
+ if (auto *ShadowD = dyn_cast<UsingShadowDecl>(*Res))
+ RealRes = ShadowD->getTargetDecl();
+ if (isa<TypeDecl>(RealRes) || isa<ObjCInterfaceDecl>(RealRes) ||
----------------
Can you use `getUnderlyingDecl` for this?
================
Comment at: clang/lib/Sema/SemaDecl.cpp:440-441
+ RealRes = ShadowD->getTargetDecl();
+ if (isa<TypeDecl>(RealRes) || isa<ObjCInterfaceDecl>(RealRes) ||
+ isa<UnresolvedUsingIfExistsDecl>(RealRes) ||
+ (AllowDeducedTemplate && getAsTypeTemplateDecl(RealRes))) {
----------------
================
Comment at: clang/lib/Sema/SemaDecl.cpp:500
+ // Recover with 'int'
+ T = Context.IntTy;
} else if (AllowDeducedTemplate) {
----------------
Mordante wrote:
> Why do you want recover instead of returning a `nullptr`?
I agree. Producing `IntTy` here is liable to result in follow-on diagnostics. It seems better to tell downstream code that you found a non-type. Can you remove this special case entirely?
================
Comment at: clang/lib/Sema/SemaDeclCXX.cpp:12119
- if (HasTypenameKeyword) {
- // If we asked for a typename and got a non-type decl, error out.
- if (!R.getAsSingle<TypeDecl>()) {
- Diag(IdentLoc, diag::err_using_typename_non_type);
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
- Diag((*I)->getUnderlyingDecl()->getLocation(),
- diag::note_using_decl_target);
- return BuildInvalid();
+ if (!IsUsingIfExists || !R.empty()) {
+ if (HasTypenameKeyword) {
----------------
It might be simpler to create the `UnresolvedUsingIfExistsDecl` earlier (before this `if`) and add it to the lookup result for the checks here and below. That would avoid some of the special-case logic here.
================
Comment at: clang/lib/Sema/SemaExpr.cpp:3146-3150
+ if (auto *EmptyD = dyn_cast<UnresolvedUsingIfExistsDecl>(D)) {
+ Diag(Loc, diag::err_use_of_empty_using_if_exists);
+ Diag(EmptyD->getLocation(), diag::note_empty_using_if_exists_here);
+ return ExprError();
+ }
----------------
I think this should instead be done by `DiagnoseUseOfDecl` / `CanUseDecl`. All the code paths we care about already go through that.
================
Comment at: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp:3195-3196
+ UnresolvedUsingIfExistsDecl *D) {
+ return UnresolvedUsingIfExistsDecl::Create(
+ SemaRef.Context, Owner, D->getLocation(), D->getDeclName());
+}
----------------
Is this reachable? I'd expect the only way we can see these is via the list of shadow declarations of the `UsingDecl`, so we should never try to instantiate one by itself.
================
Comment at: clang/lib/Sema/TreeTransform.h:14115-14123
+ NamedDecl *Target = Using->shadow_begin()->getTargetDecl();
+ if (auto *EmptyD = dyn_cast<UnresolvedUsingIfExistsDecl>(Target)) {
+ getSema().Diag(Loc, diag::err_use_of_empty_using_if_exists);
+ getSema().Diag(EmptyD->getLocation(),
+ diag::note_empty_using_if_exists_here);
+ return QualType();
+ }
----------------
We should `DiagnoseUseOfDecl` along this code path rather than adding an ad-hoc check for this one case. That would also fix another, related bug:
```
struct A { struct __attribute__((deprecated)) B {}; };
// warns that B is deprecated
struct C : A { using typename A::B; B b; };
// fails to warn that B is deprecated
template<typename T> struct D : A { using typename A::B; B b; };
D<A> da;
```
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D90188/new/
https://reviews.llvm.org/D90188
More information about the cfe-commits
mailing list