This is an archive of the discontinued LLVM Phabricator instance.

[ms] Allow more unqualified lookup of types in dependent base classes
ClosedPublic

Authored by rnk on May 20 2016, 3:40 PM.

Details

Summary

In dependent contexts where we know a type name is required, such as a
new expression, we can recover by forming a DependentNameType.

Works towards parsing atlctrlw.h, which is PR26748.

Diff Detail

Event Timeline

rnk updated this revision to Diff 58015.May 20 2016, 3:40 PM
rnk retitled this revision from to [ms] Allow more unqualified lookup of types in dependent base classes.
rnk updated this object.
rnk added reviewers: avt77, rsmith.
rnk added a subscriber: cfe-commits.
rsmith added inline comments.May 20 2016, 5:43 PM
lib/Parse/ParseDecl.cpp
2299

Maybe put the check here instead. That way, you can apply it for any DSContext.

lib/Sema/SemaDecl.cpp
507

Missing loop termination condition

rnk marked an inline comment as done.May 23 2016, 11:00 AM
rnk added inline comments.
lib/Parse/ParseDecl.cpp
2299

Done. With that change, we ended up over-accepting invalid C++ like this:

template <typename T>
struct A : T {
  C c; // MSVC rejects, C is undeclared. My patch accepted invalid.
};
struct B { typedef int C; };
template struct A<B>;

This recovery mode should only be firing inside *methods* of classes with dependent bases, so I tweaked ActOnMSVCUnknownType to do that.

rnk updated this revision to Diff 58119.May 23 2016, 11:00 AM
  • Recover in ParseImplicitInt instead
rsmith added inline comments.May 23 2016, 12:37 PM
include/clang/Sema/Sema.h
1536–1537

Can you remove this now, along with the corresponding recovery path in the parser? The new recovery path seems like it should be able to cover a superset of cases.

lib/Sema/SemaDecl.cpp
524–527

Instead of doing this, could you synthesizeCurrentNestedNameSpecifier as ActOnDelayedDefaultTemplateArg does, and just check for the existence of a dependent base class here? That way you should do the right thing even if there are multiple dependent base classes.

rnk updated this revision to Diff 58169.May 23 2016, 4:42 PM
rnk marked an inline comment as done.
  • Share the MSVC compatibility hack between the inside a method case and the default type template argument case
rsmith added inline comments.May 23 2016, 6:24 PM
include/clang/Sema/Sema.h
1539

form -> form a

lib/Sema/SemaDecl.cpp
512

refering -> referring

532–534

Maybe make this an else for the above if.

573–576

Doesn't seem to be done? I can easily believe there's a good reason why we want two different paths for building a recovery nested name specifier, but I'd like to know what it is at least.

rnk marked 4 inline comments as done.May 24 2016, 2:03 PM
rnk added inline comments.
lib/Sema/SemaDecl.cpp
573–576

We should already be handling the case you are thinking of. We don't recover by using a dependent base in the NNS. We recover by using the class *deriving* from those bases in the NNS, like this:

template <typename T, typename U>
struct A : T, U {
  void *p() { return new /*A::*/ X; } // We hallucinate the commented out specifier
};

synthesizeCurrentNestedNameSpecifier is doing something different. It's just looking for the nearest parent scope that can legitimately form an NNS, which means global scope, namespace scope, or record scope, mainly by skipping function scopes. This is sort of what it looks like:

template <typename T = /*::*/ X> struct A { ... };
namespace ns {
template <typename T = /*ns::*/ X> struct B { ... };
}
rnk updated this revision to Diff 58315.May 24 2016, 2:04 PM
  • nits
rnk updated this revision to Diff 58316.May 24 2016, 2:16 PM
  • fix the diff
rsmith accepted this revision.May 24 2016, 2:20 PM
rsmith edited edge metadata.
This revision is now accepted and ready to land.May 24 2016, 2:20 PM
This revision was automatically updated to reflect the committed changes.