diff options
author | Reid Kleckner <reid@kleckner.net> | 2013-10-15 18:38:02 +0000 |
---|---|---|
committer | Reid Kleckner <reid@kleckner.net> | 2013-10-15 18:38:02 +0000 |
commit | 8690cee218a59d3f6eaca17b9c25d03a52ebacaa (patch) | |
tree | 095cec0890ba59abdf92c1781f5b1b9884f4ef22 /test/SemaTemplate/ms-lookup-template-base-classes.cpp | |
parent | e96a7b4d99e8737b1dc8a3bd07038f885bc4263b (diff) | |
download | clang-8690cee218a59d3f6eaca17b9c25d03a52ebacaa.tar.gz |
ms-compat: Fix taking the address of a member of a dependent base
If unqualified id lookup fails while parsing a class template with a
dependent base, clang with -fms-compatibility will pretend the user
prefixed the name with 'this->' in order to delay the lookup. However,
if there was a unary ampersand, Sema::ActOnDependentIdExpression() will
create a DependentDeclRefExpr, which is not what we wanted at all. Fix
this by building the CXXDependentScopeMemberExpr directly instead.
In order to be fully MSVC compatible, we would have to defer all
attempts at name lookup to instantiation time. However, until we have
real problems with system headers that can't be parsed, we'll put off
implementing that.
Fixes PR16014.
Reviewers: rsmith
Differential Revision: http://llvm-reviews.chandlerc.com/D1892
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@192727 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/SemaTemplate/ms-lookup-template-base-classes.cpp')
-rw-r--r-- | test/SemaTemplate/ms-lookup-template-base-classes.cpp | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/test/SemaTemplate/ms-lookup-template-base-classes.cpp b/test/SemaTemplate/ms-lookup-template-base-classes.cpp index cb1a7f50b7..72ce056063 100644 --- a/test/SemaTemplate/ms-lookup-template-base-classes.cpp +++ b/test/SemaTemplate/ms-lookup-template-base-classes.cpp @@ -196,3 +196,43 @@ void f() { } } // namespace PR12701 + +namespace PR16014 { + +struct A { + int a; + static int sa; +}; +template <typename T> struct B : T { + int foo() { return a; } + int *bar() { return &a; } + int baz() { return T::a; } + int T::*qux() { return &T::a; } + static int T::*stuff() { return &T::a; } + static int stuff1() { return T::sa; } + static int *stuff2() { return &T::sa; } +}; + +template <typename T> struct C : T { + int foo() { return b; } // expected-error {{no member named 'b' in 'PR16014::C<PR16014::A>'}} + int *bar() { return &b; } // expected-error {{no member named 'b' in 'PR16014::C<PR16014::A>'}} + int baz() { return T::b; } // expected-error {{no member named 'b' in 'PR16014::A'}} + int T::*qux() { return &T::b; } // expected-error {{no member named 'b' in 'PR16014::A'}} + int T::*fuz() { return &U::a; } // expected-error {{use of undeclared identifier 'U'}} +}; + +template struct B<A>; +template struct C<A>; // expected-note-re 1+ {{in instantiation of member function 'PR16014::C<PR16014::A>::.*' requested here}} + +template <typename T> struct D : T { + struct Inner { + int foo() { + // FIXME: MSVC can find this in D's base T! Even worse, if ::sa exists, + // clang will use it instead. + return sa; // expected-error {{use of undeclared identifier 'sa'}} + } + }; +}; +template struct D<A>; + +} |