tbaeder created this revision. tbaeder added reviewers: aaron.ballman, rsmith, rjmccall, rtrieu. Herald added subscribers: lxfind, jdoerfert. tbaeder requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Hi, when trying to access a member of a namespace/class/struct/enum, clang currently just prints that the given namespace does not have a member with the given name, for example: ./enum.cpp:12:7: error: no member named 'b' in 'Foo' foo.b = 10; ~~~ ^ 1 error generated. However, for programmers it is usually also important to know where the namespace has been declared, e.g. in the example above it would be useful to know where `foo`'s type has been declared. The following patch adds support for this by simply printing a note: ./enum.cpp:12:7: error: no member named 'b' in 'Foo' foo.b = 10; ~~~ ^ ./enum.cpp:3:7: note: 'Foo' declared here class Foo { ^~~ 1 error generated. That is of course a very simple example, but I think this adds value in real-world scenarios. The patch is unfortunately all over the place and mostly updating test cases with the additional expected note. In addition to the usual review I'd like opinions on the following open questions: - There are now three places where the patch adds the exact same code, would a helper function (in `Sema`?) be better and if so, where is the best place for it? - The notes are pretty clunky to read when the namespace is created by a lambda: " note: '(lambda at enum.cpp:41:12)' declared here" - should lambdas simply be ignored (how to do that?) or should I handle them differently? - The patch only emits the note if clang does not output a typo correction. I thought it might not be as useful in this case since it would clutter the output and chances are that the typo fix _is_ the right thing to show. Opinions on this? Thanks, Timm Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D95536 Files: clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaExprMember.cpp clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp clang/test/CXX/class.access/class.friend/p1.cpp clang/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp clang/test/CXX/drs/dr1xx.cpp clang/test/CXX/drs/dr21xx.cpp clang/test/CXX/drs/dr3xx.cpp clang/test/CXX/drs/dr6xx.cpp clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp clang/test/CXX/module/module.interface/p2.cpp clang/test/CXX/special/class.copy/p28-cxx11.cpp clang/test/CXX/special/class.dtor/p10-0x.cpp clang/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp clang/test/CXX/temp/temp.res/temp.local/p3.cpp clang/test/CXX/temp/temp.res/temp.local/p9.cpp clang/test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp clang/test/Misc/diag-template.cpp clang/test/Modules/Inputs/redecl_namespaces_left.h clang/test/Modules/cxx-templates.cpp clang/test/Modules/module-private.cpp clang/test/Modules/redecl-namespaces.mm clang/test/OpenMP/target_map_messages.cpp clang/test/OpenMP/target_teams_map_messages.cpp clang/test/PCH/decl-attrs.cpp clang/test/Parser/recovery.c clang/test/Parser/recovery.cpp clang/test/Sema/MicrosoftExtensions.c clang/test/Sema/anonymous-struct-union.c clang/test/Sema/typo-correction-ambiguity.cpp clang/test/Sema/typo-correction-no-hang.cpp clang/test/Sema/typo-correction-recursive.cpp clang/test/SemaCXX/MicrosoftExtensions.cpp clang/test/SemaCXX/anonymous-union.cpp clang/test/SemaCXX/attr-cleanup.cpp clang/test/SemaCXX/co_await-range-for.cpp clang/test/SemaCXX/constructor-initializer.cpp clang/test/SemaCXX/conversion-function.cpp clang/test/SemaCXX/coroutines.cpp clang/test/SemaCXX/cxx1y-deduced-return-type.cpp clang/test/SemaCXX/cxx1y-generic-lambdas.cpp clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp clang/test/SemaCXX/friend.cpp clang/test/SemaCXX/invalid-member-expr.cpp clang/test/SemaCXX/member-operator-expr.cpp clang/test/SemaCXX/missing-members.cpp clang/test/SemaCXX/nested-name-spec.cpp clang/test/SemaCXX/pseudo-destructors.cpp clang/test/SemaCXX/qualified-id-lookup.cpp clang/test/SemaCXX/typo-correction-delayed.cpp clang/test/SemaCXX/typo-correction.cpp clang/test/SemaCXX/unknown-type-name.cpp clang/test/SemaObjCXX/deduction.mm clang/test/SemaObjCXX/interface-return-type.mm clang/test/SemaTemplate/attributes.cpp clang/test/SemaTemplate/cxx1z-using-declaration.cpp clang/test/SemaTemplate/dependent-base-classes.cpp clang/test/SemaTemplate/instantiate-method.cpp clang/test/SemaTemplate/instantiate-non-dependent-types.cpp clang/test/SemaTemplate/member-access-ambig.cpp clang/test/SemaTemplate/member-access-expr.cpp clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp
Index: clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp =================================================================== --- clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp +++ clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp @@ -200,7 +200,7 @@ namespace PR16014 { -struct A { +struct A { // expected-note {{declared here}} int a; static int sa; }; @@ -226,7 +226,8 @@ }; template struct B<A>; -template struct C<A>; // expected-note-re 1+ {{in instantiation of member function 'PR16014::C<PR16014::A>::{{.*}}' requested here}} +template struct C<A>; // expected-note-re 1+ {{in instantiation of member function 'PR16014::C<PR16014::A>::{{.*}}' requested here}} \ + // expected-note 2 {{declared here}} template <typename T> struct D : T { struct Inner { Index: clang/test/SemaTemplate/member-access-expr.cpp =================================================================== --- clang/test/SemaTemplate/member-access-expr.cpp +++ clang/test/SemaTemplate/member-access-expr.cpp @@ -43,7 +43,7 @@ } -struct OtherBase { }; +struct OtherBase { }; // expected-note 2 {{declared here}} struct X1 : Base, OtherBase { typedef OtherBase CrazyBase; @@ -59,7 +59,7 @@ } -struct X2 { +struct X2 { // expected-note {{declared here}} operator int() const; }; Index: clang/test/SemaTemplate/member-access-ambig.cpp =================================================================== --- clang/test/SemaTemplate/member-access-ambig.cpp +++ clang/test/SemaTemplate/member-access-ambig.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused-comparison %s // PR8439 -class A +class A // expected-note {{declared here}} { }; Index: clang/test/SemaTemplate/instantiate-non-dependent-types.cpp =================================================================== --- clang/test/SemaTemplate/instantiate-non-dependent-types.cpp +++ clang/test/SemaTemplate/instantiate-non-dependent-types.cpp @@ -32,13 +32,13 @@ } }; -class Q { +class Q { // expected-note 2 {{declared here}} public: Q() {} ~Q() {} }; -enum Colors {red, green, blue}; +enum Colors {red, green, blue}; // expected-note {{declared here}} C<Q, int> dummy; C<Q, Colors> dummyColors; Index: clang/test/SemaTemplate/instantiate-method.cpp =================================================================== --- clang/test/SemaTemplate/instantiate-method.cpp +++ clang/test/SemaTemplate/instantiate-method.cpp @@ -184,7 +184,7 @@ } namespace PR22040 { - template <typename T> struct Foobar { + template <typename T> struct Foobar { // expected-note 3 {{here}} template <> void bazqux(typename T::type) {} // expected-error 2{{cannot be used prior to '::' because it has no members}} }; Index: clang/test/SemaTemplate/dependent-base-classes.cpp =================================================================== --- clang/test/SemaTemplate/dependent-base-classes.cpp +++ clang/test/SemaTemplate/dependent-base-classes.cpp @@ -56,7 +56,7 @@ int foo() { class NoDepBase::Nested nested; // expected-error{{no class named 'Nested' in 'NoDepBase<T>'}} typedef typename NoDepBase::template MemberTemplate<T>::type type; // expected-error{{no member named 'MemberTemplate' in 'NoDepBase<T>'}} - return NoDepBase::a; // expected-error{{no member named 'a' in 'NoDepBase<T>'}} + return NoDepBase::a; // expected-error{{no member named 'a' in 'NoDepBase<T>'}} expected-note@-4 {{here}} } }; } Index: clang/test/SemaTemplate/cxx1z-using-declaration.cpp =================================================================== --- clang/test/SemaTemplate/cxx1z-using-declaration.cpp +++ clang/test/SemaTemplate/cxx1z-using-declaration.cpp @@ -16,7 +16,7 @@ } // Test using non-type members from pack of base classes. -template<typename ...T> struct A : T... { +template<typename ...T> struct A : T... { // expected-note {{declared here}} using T::T ...; // expected-note 2{{inherited here}} using T::operator() ...; using T::operator T* ...; @@ -158,7 +158,7 @@ // Test partial substitution into class-scope pack. template<typename ...T> auto lambda1() { return [](auto x) { - struct A : T::template X<decltype(x)>... { // expected-note 1+{{instantiation of}} + struct A : T::template X<decltype(x)>... { // expected-note 1+{{instantiation of}} expected-note {{declared here}} using T::template X<decltype(x)>::f ...; using typename T::template X<decltype(x)>::type ...; void g(int n) { f(n); } // expected-error {{empty pack}} expected-error {{expected 2, have 1}} expected-error {{ambiguous}} Index: clang/test/SemaTemplate/attributes.cpp =================================================================== --- clang/test/SemaTemplate/attributes.cpp +++ clang/test/SemaTemplate/attributes.cpp @@ -77,7 +77,7 @@ template<typename T> struct [[clang::preferred_name(X), clang::preferred_name(Y)]] C; template<typename T> struct [[clang::preferred_name(const X)]] C; // expected-error {{argument 'const preferred_name::X'}} template<typename T> struct [[clang::preferred_name(Z)]] C; // expected-error {{argument 'preferred_name::Z' (aka 'const C<double>')}} - template<typename T> struct C {}; + template<typename T> struct C {}; // expected-note 3 {{declared here}} // CHECK: ClassTemplateDecl {{.*}} <line:[[@LINE-10]]:{{.*}} C // CHECK: ClassTemplateSpecializationDecl {{.*}} struct C definition @@ -113,7 +113,7 @@ template<typename T> struct D; using DInt = D<int>; template<typename T> struct __attribute__((__preferred_name__(DInt))) D {}; - template struct D<int>; + template struct D<int>; // expected-note {{declared here}} int use_dint = D<int>().get(); // expected-error {{no member named 'get' in 'preferred_name::DInt'}} template<typename T> struct MemberTemplate { Index: clang/test/SemaObjCXX/interface-return-type.mm =================================================================== --- clang/test/SemaObjCXX/interface-return-type.mm +++ clang/test/SemaObjCXX/interface-return-type.mm @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify @class NSObject; -template<typename T> struct C { +template<typename T> struct C { // expected-note {{declared here}} static T f(); // expected-error {{interface type 'NSObject' cannot be returned by value; did you forget * in 'NSObject'?}} }; int g() { NSObject *x = C<NSObject>::f(); }//expected-error {{no member named 'f' in 'C<NSObject>'}} expected-note {{in instantiation of template class 'C<NSObject>' requested here}} Index: clang/test/SemaObjCXX/deduction.mm =================================================================== --- clang/test/SemaObjCXX/deduction.mm +++ clang/test/SemaObjCXX/deduction.mm @@ -36,7 +36,7 @@ template <typename T> struct RemovePointer<T*> { typedef T type; }; - template <typename A, typename B> struct is_same {}; + template <typename A, typename B> struct is_same {}; // expected-note 2 {{declared here}} template <typename A> struct is_same<A,A> { static void foo(); }; Index: clang/test/SemaCXX/unknown-type-name.cpp =================================================================== --- clang/test/SemaCXX/unknown-type-name.cpp +++ clang/test/SemaCXX/unknown-type-name.cpp @@ -4,7 +4,7 @@ // PR3990 namespace N { - struct Wibble { + struct Wibble { // expected-note {{here}} }; typedef Wibble foo; Index: clang/test/SemaCXX/typo-correction.cpp =================================================================== --- clang/test/SemaCXX/typo-correction.cpp +++ clang/test/SemaCXX/typo-correction.cpp @@ -259,7 +259,7 @@ s.methodd(&b); // expected-error{{no member named 'methodd' in 'b6956809_test1::S1'; did you mean 'method'}} } - struct S2 { + struct S2 { // expected-note {{here}} S2(); void method(A*) const; private: Index: clang/test/SemaCXX/typo-correction-delayed.cpp =================================================================== --- clang/test/SemaCXX/typo-correction-delayed.cpp +++ clang/test/SemaCXX/typo-correction-delayed.cpp @@ -4,7 +4,7 @@ struct A {}; struct B {}; -struct D { +struct D { // expected-note 4 {{declared here}} A fizbin; // expected-note 2 {{declared here}} A foobar; // expected-note 2 {{declared here}} B roxbin; // expected-note 2 {{declared here}} @@ -65,7 +65,7 @@ // Test that initializer expressions are handled correctly and that the type // being initialized is taken into account when choosing a correction. namespace initializerCorrections { -struct Node { +struct Node { // expected-note {{declared here}} string text() const; // Node* Next() is not implemented yet }; @@ -85,7 +85,7 @@ LinkedNode *next = node->Next(); // expected-error {{no member named 'Next' in 'initializerCorrections::LinkedNode'; did you mean 'next'?}} } -struct NestedNode { +struct NestedNode { // expected-note {{declared here}} NestedNode* Nest(); NestedNode* next(); string text() const; @@ -111,7 +111,7 @@ namespace foo {} void test_paren_suffix() { - foo::bar({5, 6}); // expected-error-re {{no member named 'bar' in namespace 'foo'{{$}}}} + foo::bar({5, 6}); // expected-error-re {{no member named 'bar' in namespace 'foo'{{$}}}} expected-note@-2 {{here}} #if __cplusplus <= 199711L // expected-error@-2 {{expected expression}} #endif Index: clang/test/SemaCXX/qualified-id-lookup.cpp =================================================================== --- clang/test/SemaCXX/qualified-id-lookup.cpp +++ clang/test/SemaCXX/qualified-id-lookup.cpp @@ -83,7 +83,7 @@ } // PR clang/3291 -namespace a { +namespace a { namespace a { // A1 namespace a { // A2 int i; // expected-note{{'a::a::a::i' declared here}} @@ -94,9 +94,9 @@ void test_a() { a::a::i = 3; // expected-error{{no member named 'i' in namespace 'a::a'; did you mean 'a::a::a::i'?}} a::a::a::i = 4; - a::a::j = 3; // expected-error-re{{no member named 'j' in namespace 'a::a'{{$}}}} + a::a::j = 3; // expected-error-re{{no member named 'j' in namespace 'a::a'{{$}}}} expected-note@-10 {{here}} } - + struct Undef { // expected-note{{definition of 'Undef' is not complete until the closing '}'}} typedef int type; Index: clang/test/SemaCXX/pseudo-destructors.cpp =================================================================== --- clang/test/SemaCXX/pseudo-destructors.cpp +++ clang/test/SemaCXX/pseudo-destructors.cpp @@ -129,7 +129,7 @@ template<typename T> void f(T *p) { p->~G(); } // expected-error {{no member named '~Y'}} void h1(Y *p) { p->~G(); } void h2(Y *p) { f(p); } - namespace N { struct G{}; } + namespace N { struct G{}; } // expected-note {{declared here}} void h3(N::G *p) { p->~G(); } void h4(N::G *p) { f(p); } // expected-note {{instantiation of}} } @@ -151,7 +151,7 @@ template<typename T> void f(T *p) { p->~G<int>(); } // expected-error {{no member named '~Y'}} void h1(Y<int> *p) { p->~G<int>(); } void h2(Y<int> *p) { f(p); } - namespace N { template<typename T> struct G {}; } + namespace N { template<typename T> struct G {}; } // expected-note {{declared here}} void h3(N::G<int> *p) { p->~G<int>(); } void h4(N::G<int> *p) { f(p); } // expected-note {{instantiation of}} } Index: clang/test/SemaCXX/nested-name-spec.cpp =================================================================== --- clang/test/SemaCXX/nested-name-spec.cpp +++ clang/test/SemaCXX/nested-name-spec.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c++98 -verify -fblocks %s +// RUN: %clang_cc1 -fsyntax-only -std=c++98 -verify -fblocks %s namespace A { struct C { static int cx; @@ -54,7 +54,7 @@ void f2() { A:: ; // expected-error {{expected unqualified-id}} - A::C::undef = 0; // expected-error {{no member named 'undef'}} + A::C::undef = 0; // expected-error {{no member named 'undef'}} expected-note@3 {{here}} ::A::C::cx = 0; int x = ::A::ax = A::C::cx; x = sizeof(A::C); @@ -91,7 +91,7 @@ N::x = 0; // expected-error {{'N' is not a class, namespace, or enumeration}} { int A; A::ax = 0; } { typedef int A; A::ax = 0; } // expected-error{{'A' (aka 'int') is not a class, namespace, or enumeration}} - { typedef A::C A; A::ax = 0; } // expected-error {{no member named 'ax'}} + { typedef A::C A; A::ax = 0; } // expected-error {{no member named 'ax'}} expected-note@3 {{here}} { typedef A::C A; A::cx = 0; } } @@ -431,7 +431,7 @@ // expected-error{{'ENUMERATOR' is not a class, namespace, or enumeration}} \ int x3 = ns::an_enumeration::X; // expected-warning{{use of enumeration in a nested name specifier is a C++11 extension}} \ - // expected-error{{no member named 'X'}} + // expected-error{{no member named 'X'}} expected-note@-10 {{here}} enum enumerator_2 { ENUMERATOR_2 @@ -439,7 +439,7 @@ int x4 = enumerator_2::ENUMERATOR_2; // expected-warning{{use of enumeration in a nested name specifier is a C++11 extension}} int x5 = enumerator_2::X2; // expected-warning{{use of enumeration in a nested name specifier is a C++11 extension}} \ - // expected-error{{no member named 'X2' in 'PR16951::enumerator_2'}} + // expected-error{{no member named 'X2' in 'PR16951::enumerator_2'}} expected-note@-5 {{here}} } Index: clang/test/SemaCXX/missing-members.cpp =================================================================== --- clang/test/SemaCXX/missing-members.cpp +++ clang/test/SemaCXX/missing-members.cpp @@ -8,7 +8,7 @@ } void f() { - A::B::i; // expected-error {{no member named 'i' in namespace 'A::B'}} + A::B::i; // expected-error {{no member named 'i' in namespace 'A::B'}} expected-note@3 {{here}} A::B::C::i; // expected-error {{no member named 'i' in 'A::B::C'}} ::i; // expected-error {{no member named 'i' in the global namespace}} } @@ -22,7 +22,8 @@ // FIXME: The typo corrections below should be suppressed since A::B::C // doesn't have a member named D. B::B::C::D; // expected-error {{no member named 'C' in 'B::B'; did you mean 'A::B::C'?}} \ - // expected-error-re {{no member named 'D' in 'A::B::C'{{$}}}} + // expected-error-re {{no member named 'D' in 'A::B::C'{{$}}}} \ + // expected-note@4 {{here}} ::C::D; // expected-error-re {{no member named 'C' in the global namespace{{$}}}} } @@ -33,12 +34,12 @@ using A::B::D; // expected-error {{no member named 'D' in namespace 'A::B'}} -struct S : A::B::C { - using A::B::C::f; // expected-error {{no member named 'f' in 'A::B::C'}} - +struct S : A::B::C { + using A::B::C::f; // expected-error {{no member named 'f' in 'A::B::C'}} expected-note@4 {{here}} + }; -struct S1 {}; +struct S1 {}; // expected-note {{declared here}} struct S2 : S1 {}; Index: clang/test/SemaCXX/member-operator-expr.cpp =================================================================== --- clang/test/SemaCXX/member-operator-expr.cpp +++ clang/test/SemaCXX/member-operator-expr.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -class X { +class X { // expected-note 4 {{declared here}} public: int operator++(); operator int(); @@ -31,4 +31,4 @@ namespace pr13157 { class A { public: void operator()(int x, int y = 2, ...) {} }; void f() { A()(1); } -} \ No newline at end of file +} Index: clang/test/SemaCXX/invalid-member-expr.cpp =================================================================== --- clang/test/SemaCXX/invalid-member-expr.cpp +++ clang/test/SemaCXX/invalid-member-expr.cpp @@ -39,7 +39,7 @@ #endif } - struct string { + struct string { // expected-note {{declared here}} class iterator {}; }; Index: clang/test/SemaCXX/friend.cpp =================================================================== --- clang/test/SemaCXX/friend.cpp +++ clang/test/SemaCXX/friend.cpp @@ -206,7 +206,7 @@ ::test10::f10_a(); ::test10::f10_b(); ::test10::f10_c(); - ::test10::f10_d(); // expected-error {{no member named 'f10_d'}} + ::test10::f10_d(); // expected-error {{no member named 'f10_d'}} expected-note@169 {{here}} f10_a(x); f10_b(x); @@ -216,7 +216,7 @@ ::test10::f10_a(x); ::test10::f10_b(x); ::test10::f10_c(x); - ::test10::f10_d(x); // expected-error {{no type named 'f10_d'}} + ::test10::f10_d(x); // expected-error {{no type named 'f10_d'}} expected-note@169 {{here}} } struct Y : X { Index: clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp =================================================================== --- clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp +++ clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp @@ -398,7 +398,7 @@ #ifndef PRECXX11 namespace template_vars_in_template { -template <int> struct TakesInt {}; +template <int> struct TakesInt {}; // expected-note {{declared here}} template <class T2> struct S { Index: clang/test/SemaCXX/cxx1y-generic-lambdas.cpp =================================================================== --- clang/test/SemaCXX/cxx1y-generic-lambdas.cpp +++ clang/test/SemaCXX/cxx1y-generic-lambdas.cpp @@ -225,7 +225,7 @@ // Here, the conversion function is named 'operator auto (*)(int)', and // there is no way to write that name in valid C++. - auto M = [](auto a) -> auto { return a; }; + auto M = [](auto a) -> auto { return a; }; // expected-note {{declared here}} M.operator F*(); // expected-error {{no member named 'operator int (*)(int)'}} } } Index: clang/test/SemaCXX/cxx1y-deduced-return-type.cpp =================================================================== --- clang/test/SemaCXX/cxx1y-deduced-return-type.cpp +++ clang/test/SemaCXX/cxx1y-deduced-return-type.cpp @@ -10,7 +10,7 @@ auto h() -> auto *; auto *h(); -struct Conv1 { +struct Conv1 { // expected-note {{declared here}} operator auto(); // expected-note {{declared here}} } conv1; int conv1a = conv1; // expected-error {{function 'operator auto' with deduced return type cannot be used before it is defined}} @@ -62,7 +62,7 @@ operator auto() { return 0; } operator auto *() { return this; } }; -struct JustTemplateOp { +struct JustTemplateOp { // expected-note 2 {{declared here}} template <typename T> operator T(); template <typename T> operator T *(); }; Index: clang/test/SemaCXX/coroutines.cpp =================================================================== --- clang/test/SemaCXX/coroutines.cpp +++ clang/test/SemaCXX/coroutines.cpp @@ -103,7 +103,7 @@ template <> struct std::experimental::coroutine_traits<double, int> { - struct promise_type {}; + struct promise_type {}; // expected-note 2 {{declared here}} }; double bad_promise_type_2(int) { // expected-error {{no member named 'initial_suspend'}} co_yield 0; // expected-error {{no member named 'yield_value' in 'std::experimental::coroutine_traits<double, int>::promise_type'}} @@ -125,9 +125,9 @@ struct yielded_thing { const char *p; short a, b; }; -struct not_awaitable {}; +struct not_awaitable {}; // expected-note 3 {{declared here}} -struct promise { +struct promise { // expected-note {{declared here}} void get_return_object(); suspend_always initial_suspend(); suspend_always final_suspend() noexcept; @@ -138,7 +138,7 @@ void unhandled_exception(); }; -struct promise_void { +struct promise_void { // expected-note {{declared here}} void get_return_object(); suspend_always initial_suspend(); suspend_always final_suspend() noexcept; @@ -422,7 +422,7 @@ awaitable operator co_await(indirectly_awaitable); // expected-note {{should be declared prior to}} template void await_template(indirectly_awaitable); - struct not_awaitable {}; + struct not_awaitable {}; // expected-note {{declared here}} template void await_template(not_awaitable); // expected-note {{instantiation}} template<typename T> void await_template_2(T t) { @@ -433,7 +433,7 @@ template void await_template_2(outer); struct transform_awaitable {}; - struct transformed {}; + struct transformed {}; // expected-note 4 {{declared here}} struct transform_promise { typedef transform_awaitable await_arg; @@ -566,7 +566,7 @@ } } -struct bad_promise_1 { +struct bad_promise_1 { // expected-note {{declared here}} suspend_always initial_suspend(); suspend_always final_suspend() noexcept; void unhandled_exception(); @@ -1425,11 +1425,11 @@ co_yield 42; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} } -struct missing_await_ready { +struct missing_await_ready { // expected-note {{declared here}} void await_suspend(std::experimental::coroutine_handle<>); void await_resume(); }; -struct missing_await_suspend { +struct missing_await_suspend { // expected-note {{declared here}} bool await_ready(); void await_resume(); }; Index: clang/test/SemaCXX/conversion-function.cpp =================================================================== --- clang/test/SemaCXX/conversion-function.cpp +++ clang/test/SemaCXX/conversion-function.cpp @@ -459,7 +459,7 @@ } a; A::S s = a; // expected-error {{no viable conversion from 'struct A' to 'A::S'}} A::E e = a; - bool k1 = e == A::e; // expected-error {{no member named 'e'}} + bool k1 = e == A::e; // expected-error {{no member named 'e'}} expected-note@-10 {{here}} bool k2 = e.n == 0; } Index: clang/test/SemaCXX/constructor-initializer.cpp =================================================================== --- clang/test/SemaCXX/constructor-initializer.cpp +++ clang/test/SemaCXX/constructor-initializer.cpp @@ -245,7 +245,7 @@ #endif // expected-note@-5 {{candidate constructor (the implicit default constructor) not viable}} - class B : public A { + class B : public A { // expected-note {{declared here}} public: B(const String& s, int e=0) // expected-error {{unknown type name}} : A(e), m_String(s) , m_ErrorStr(__null) {} // expected-error {{no matching constructor}} expected-error {{does not name}} Index: clang/test/SemaCXX/co_await-range-for.cpp =================================================================== --- clang/test/SemaCXX/co_await-range-for.cpp +++ clang/test/SemaCXX/co_await-range-for.cpp @@ -17,7 +17,7 @@ template <class Iter> struct IncTag { IncTag() = delete; }; template <class Iter, bool Delete = false> -struct CoawaitTag { CoawaitTag() = delete; }; +struct CoawaitTag { CoawaitTag() = delete; }; // expected-note {{declared here}} template <class T> struct Iter { Index: clang/test/SemaCXX/attr-cleanup.cpp =================================================================== --- clang/test/SemaCXX/attr-cleanup.cpp +++ clang/test/SemaCXX/attr-cleanup.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 %s -verify -fsyntax-only -Wno-gcc-compat -namespace N { +namespace N { // expected-note {{here}} void c1(int *a) {} } Index: clang/test/SemaCXX/anonymous-union.cpp =================================================================== --- clang/test/SemaCXX/anonymous-union.cpp +++ clang/test/SemaCXX/anonymous-union.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s -struct X { +struct X { // expected-note {{declared here}} union { float f3; double d2; Index: clang/test/SemaCXX/MicrosoftExtensions.cpp =================================================================== --- clang/test/SemaCXX/MicrosoftExtensions.cpp +++ clang/test/SemaCXX/MicrosoftExtensions.cpp @@ -246,7 +246,7 @@ C::C(); // expected-warning{{extra qualification on member 'C'}} }; -struct StructWithProperty { +struct StructWithProperty { // expected-note 2 {{declared here}} __declspec(property(get=GetV)) int V1; __declspec(property(put=SetV)) int V2; __declspec(property(get=GetV, put=SetV_NotExist)) int V3; Index: clang/test/Sema/typo-correction-recursive.cpp =================================================================== --- clang/test/Sema/typo-correction-recursive.cpp +++ clang/test/Sema/typo-correction-recursive.cpp @@ -20,7 +20,7 @@ int m_n; }; -class Z +class Z // expected-note {{here}} { public: const Y& getY0() const { return m_y0; } // expected-note {{'getY0' declared here}} @@ -73,7 +73,7 @@ int helpMe(); int helpBe(); }; -class Ambiguous { +class Ambiguous { // expected-note 2 {{here}} public: int calculateA(); int calculateB(); @@ -94,7 +94,7 @@ } -class DeepAmbiguityHelper { +class DeepAmbiguityHelper { // expected-note {{here}} public: DeepAmbiguityHelper& help1(); DeepAmbiguityHelper& help2(); Index: clang/test/Sema/typo-correction-no-hang.cpp =================================================================== --- clang/test/Sema/typo-correction-no-hang.cpp +++ clang/test/Sema/typo-correction-no-hang.cpp @@ -15,7 +15,7 @@ } // Similar reproducer. -class A { +class A { // expected-note 1 {{here}} public: int minut() const = delete; int hour() const = delete; @@ -24,7 +24,7 @@ int latit() const; }; -class B { +class B { // expected-note 2 {{here}} public: A depar() const { return A(); } }; Index: clang/test/Sema/typo-correction-ambiguity.cpp =================================================================== --- clang/test/Sema/typo-correction-ambiguity.cpp +++ clang/test/Sema/typo-correction-ambiguity.cpp @@ -13,7 +13,7 @@ void testAmbiguousNoSuggestions() { - AmbiguousCorrection::method_Ace(); // expected-error {{no member named 'method_Ace' in namespace 'AmbiguousCorrection'}} + AmbiguousCorrection::method_Ace(); // expected-error {{no member named 'method_Ace' in namespace 'AmbiguousCorrection'}} expected-note@7 {{here}} } namespace MultipleCorrectionsButNotAmbiguous Index: clang/test/Sema/anonymous-struct-union.c =================================================================== --- clang/test/Sema/anonymous-struct-union.c +++ clang/test/Sema/anonymous-struct-union.c @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -struct X { +struct X { // expected-note {{here}} union { float f3; double d2; Index: clang/test/Sema/MicrosoftExtensions.c =================================================================== --- clang/test/Sema/MicrosoftExtensions.c +++ clang/test/Sema/MicrosoftExtensions.c @@ -62,7 +62,7 @@ long f; } NESTED6; -struct test { +struct test { // expected-note 2 {{here}} int c; struct nested2; // expected-warning {{anonymous structs are a Microsoft extension}} NESTED6; // expected-warning {{anonymous unions are a Microsoft extension}} Index: clang/test/Parser/recovery.cpp =================================================================== --- clang/test/Parser/recovery.cpp +++ clang/test/Parser/recovery.cpp @@ -36,7 +36,8 @@ 5int m = { l }, n = m; // expected-error {{unqualified-id}} namespace MissingBrace { - struct S { // expected-error {{missing '}' at end of definition of 'MissingBrace::S'}} + struct S { // expected-error {{missing '}' at end of definition of 'MissingBrace::S'}} \ + // expected-note {{declared here}} int f(); // }; Index: clang/test/Parser/recovery.c =================================================================== --- clang/test/Parser/recovery.c +++ clang/test/Parser/recovery.c @@ -21,7 +21,7 @@ // rdar://6094870 void test(int a) { - struct { int i; } x; + struct { int i; } x; // expected-note 3 {{declared here}} if (x.hello) // expected-error {{no member named 'hello'}} test(0); Index: clang/test/PCH/decl-attrs.cpp =================================================================== --- clang/test/PCH/decl-attrs.cpp +++ clang/test/PCH/decl-attrs.cpp @@ -31,8 +31,10 @@ template<typename T> T forget(T t) { return t; } void f() { - forget(y).foo(); // expected-error {{no member named 'foo' in 'preferred_name::Y'}} - forget(z).foo(); // expected-error {{no member named 'foo' in 'preferred_name::Z'}} + forget(y).foo(); // expected-error {{no member named 'foo' in 'preferred_name::Y'}} \ + // expected-note@11 {{declared here}} + forget(z).foo(); // expected-error {{no member named 'foo' in 'preferred_name::Z'}} \ + // expected-note@11 {{declared here}} } } Index: clang/test/OpenMP/target_teams_map_messages.cpp =================================================================== --- clang/test/OpenMP/target_teams_map_messages.cpp +++ clang/test/OpenMP/target_teams_map_messages.cpp @@ -89,7 +89,7 @@ } }; -struct SB { +struct SB { // expected-note {{declared here}} unsigned A; unsigned B; float Arr[100]; Index: clang/test/OpenMP/target_map_messages.cpp =================================================================== --- clang/test/OpenMP/target_map_messages.cpp +++ clang/test/OpenMP/target_map_messages.cpp @@ -189,7 +189,7 @@ } }; -struct SB { +struct SB { // expected-note {{declared here}} unsigned A; unsigned B; float Arr[100]; Index: clang/test/Modules/redecl-namespaces.mm =================================================================== --- clang/test/Modules/redecl-namespaces.mm +++ clang/test/Modules/redecl-namespaces.mm @@ -4,7 +4,8 @@ void test() { A::i; A::j; - A::k; // expected-error {{no member named 'k' in namespace 'A'}} + A::k; // expected-error {{no member named 'k' in namespace 'A'}} \ + // expected-note@redecl_namespaces_left.h:1 {{here}} } // RUN: rm -rf %t Index: clang/test/Modules/module-private.cpp =================================================================== --- clang/test/Modules/module-private.cpp +++ clang/test/Modules/module-private.cpp @@ -21,8 +21,10 @@ vector<int> vec; // expected-error{{no template named 'vector'}} VisibleStruct vs; - vs.field = 0; // expected-error{{no member named 'field' in 'VisibleStruct'}} - vs.setField(1); // expected-error{{no member named 'setField' in 'VisibleStruct'}} + vs.field = 0; // expected-error{{no member named 'field' in 'VisibleStruct'}} \ + // expected-note@module_private_right.h:10 {{declared here}} + vs.setField(1); // expected-error{{no member named 'setField' in 'VisibleStruct'}} \ + // expected-note@module_private_right.h:10 {{declared here}} return hidden_var; // expected-error{{use of undeclared identifier 'hidden_var'}} } Index: clang/test/Modules/cxx-templates.cpp =================================================================== --- clang/test/Modules/cxx-templates.cpp +++ clang/test/Modules/cxx-templates.cpp @@ -85,6 +85,7 @@ // expected-error@Inputs/cxx-templates-a.h:19 {{definition of 'DefinedInBImpl' must be imported}} // expected-note@Inputs/cxx-templates-b-impl.h:1 +{{definition here is not reachable}} // expected-error@Inputs/cxx-templates-a.h:19 +{{}} + // expected-note@Inputs/cxx-templates-b-impl.h:1 {{declared here}} // expected-error@Inputs/cxx-templates-a.h:20 +{{}} PerformDelayedLookup(defined_in_b_impl); // expected-note {{in instantiation of}} Index: clang/test/Modules/Inputs/redecl_namespaces_left.h =================================================================== --- clang/test/Modules/Inputs/redecl_namespaces_left.h +++ clang/test/Modules/Inputs/redecl_namespaces_left.h @@ -1,3 +1,3 @@ -namespace A { +namespace A { // expected-note {{here}} int i; } Index: clang/test/Misc/diag-template.cpp =================================================================== --- clang/test/Misc/diag-template.cpp +++ clang/test/Misc/diag-template.cpp @@ -3,7 +3,7 @@ namespace default_args { template<typename T> struct char_traits; template<typename T> struct allocator; - template<typename T, typename = char_traits<T>, typename = allocator<T>> struct basic_string {}; + template<typename T, typename = char_traits<T>, typename = allocator<T>> struct basic_string {}; // expected-note 2 {{declared here}} typedef basic_string<char> string; @@ -15,7 +15,7 @@ } template<typename T> struct default_delete {}; - template<class T, class Deleter = default_delete<T>> class unique_ptr { + template<class T, class Deleter = default_delete<T>> class unique_ptr { // expected-note {{declared here}} public: void f() { T::error(); } // expected-error {{no member named 'error' in 'default_args::basic_string<char>'}} }; @@ -29,7 +29,7 @@ template<int A, int B = A> struct Z { int error[B]; }; // expected-error {{negative size}} Z<-1> z; // expected-note {{in instantiation of template class 'default_args::Z<-1>' requested here}} - template<template<typename> class A = allocator, template<typename> class B = A> struct Q {}; + template<template<typename> class A = allocator, template<typename> class B = A> struct Q {}; // expected-note 6 {{declared here}} void test3() { f(Q<>()).g(); // expected-error {{no member named 'g' in 'default_args::Q<>'}} f(Q<allocator>()).g(); // expected-error {{no member named 'g' in 'default_args::Q<>'}} Index: clang/test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp =================================================================== --- clang/test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp +++ clang/test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp @@ -2,7 +2,7 @@ template<typename T> struct X { - template<typename U> struct Inner { }; + template<typename U> struct Inner { }; // expected-note {{declared here}} template<typename U> void f(T, U) { } }; Index: clang/test/CXX/temp/temp.res/temp.local/p9.cpp =================================================================== --- clang/test/CXX/temp/temp.res/temp.local/p9.cpp +++ clang/test/CXX/temp/temp.res/temp.local/p9.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s struct A { - struct B { void f(); }; + struct B { void f(); }; // expected-note {{declared here}} int a; int Y; }; Index: clang/test/CXX/temp/temp.res/temp.local/p3.cpp =================================================================== --- clang/test/CXX/temp/temp.res/temp.local/p3.cpp +++ clang/test/CXX/temp/temp.res/temp.local/p3.cpp @@ -6,7 +6,7 @@ static void f(); }; -struct X0 { }; +struct X0 { }; // expected-note {{declared here}} template <class T> struct Derived: Base<int>, Base<char> { typename Derived::Base b; // expected-error{{member 'Base' found in multiple base classes of different types}} Index: clang/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp =================================================================== --- clang/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp +++ clang/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -std=c++11 -verify %s -template<typename T> struct A { +template<typename T> struct A { // expected-note {{here}} enum E : T; // expected-note {{here}} E v; E f() { return A::e1; } // expected-error {{no member named 'e1' in 'A<T>'}} @@ -74,7 +74,7 @@ void fc1() { c1 = decltype(c1)::e5; } C<long>::E c2 = C<long>::E::e5; -template<> enum class C<int>::E : int { e6 }; +template<> enum class C<int>::E : int { e6 }; // expected-note {{here}} template<typename T> enum class C<T>::E : T { e0 }; C<int>::E c3 = C<int>::E::e6; C<int>::E c4 = C<int>::E::e0; // expected-error {{no member named 'e0' in 'C<int>::E'}} Index: clang/test/CXX/special/class.dtor/p10-0x.cpp =================================================================== --- clang/test/CXX/special/class.dtor/p10-0x.cpp +++ clang/test/CXX/special/class.dtor/p10-0x.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s // PR10127/N3031 -struct A { ~A(); }; +struct A { ~A(); }; // expected-note 2 {{declared here}} struct B {}; template<typename T> void b(const T *x, const A *y) { Index: clang/test/CXX/special/class.copy/p28-cxx11.cpp =================================================================== --- clang/test/CXX/special/class.copy/p28-cxx11.cpp +++ clang/test/CXX/special/class.copy/p28-cxx11.cpp @@ -5,7 +5,7 @@ // called by a defaulted assignment operator, and the selected operator might // not be a copy or move assignment (it might be a specialization of a templated // 'operator=', for instance). -struct A { +struct A { // expected-note {{declared here}} A &operator=(const A &); template<typename T> Index: clang/test/CXX/module/module.interface/p2.cpp =================================================================== --- clang/test/CXX/module/module.interface/p2.cpp +++ clang/test/CXX/module/module.interface/p2.cpp @@ -69,22 +69,22 @@ void use() { // namespace A is implicitly exported by the export of A::g. - A::f(); // expected-error {{no member named 'f' in namespace 'A'}} + A::f(); // expected-error {{no member named 'f' in namespace 'A'}} expected-note@23 {{here}} A::g(); - A::h(); // expected-error {{no member named 'h' in namespace 'A'}} + A::h(); // expected-error {{no member named 'h' in namespace 'A'}} expected-note@23 {{here}} using namespace A::inner; // expected-error {{expected namespace name}} // namespace B and B::inner are explicitly exported using namespace B; using namespace B::inner; - B::f(); // expected-error {{no member named 'f' in namespace 'B'}} + B::f(); // expected-error {{no member named 'f' in namespace 'B'}} expected-note@29 {{here}} f(); // expected-error {{undeclared identifier 'f'}} // namespace C is not exported using namespace C; // expected-error {{expected namespace name}} // namespace D is exported, but D::f is not - D::f(); // expected-error {{no member named 'f' in namespace 'D'}} + D::f(); // expected-error {{no member named 'f' in namespace 'D'}} expected-note@37 {{here}} } int use_header() { return foo + bar::baz(); } Index: clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp =================================================================== --- clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp +++ clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -std=c++1y %s -verify -const char *has_no_member = [x("hello")] {}.x; // expected-error {{no member named 'x'}} +const char *has_no_member = [x("hello")] {}.x; // expected-error {{no member named 'x'}} \ + // expected-note {{declared here}} double f; auto with_float = [f(1.0f)] { Index: clang/test/CXX/drs/dr6xx.cpp =================================================================== --- clang/test/CXX/drs/dr6xx.cpp +++ clang/test/CXX/drs/dr6xx.cpp @@ -419,7 +419,7 @@ #if __cplusplus >= 201103L namespace dr643 { // dr643: yes - struct A { + struct A { // expected-note 2 {{declared here}} int x; auto f() -> decltype(this->x); auto f(A &a) -> decltype(a.x); Index: clang/test/CXX/drs/dr3xx.cpp =================================================================== --- clang/test/CXX/drs/dr3xx.cpp +++ clang/test/CXX/drs/dr3xx.cpp @@ -102,7 +102,7 @@ b->~B(); // expected-error {{does not match}} } - template<typename T> struct X {}; + template<typename T> struct X {}; // expected-note {{declared here}} void i(X<int>* x) { struct X {}; x->~X<int>(); @@ -119,7 +119,7 @@ y->~T1<int>(); y->~T2<int>(); } - struct Z { + struct Z { // expected-note {{Z' declared here}} template<typename T> using T2 = T; }; void k(Z *z) { @@ -130,7 +130,7 @@ // FIXME: This is valid. namespace Q { - template<typename A> struct R {}; + template<typename A> struct R {}; // expected-note {{declared here}} } template<typename A> using R = Q::R<int>; void qr(Q::R<int> x) { x.~R<char>(); } // expected-error {{no member named}} Index: clang/test/CXX/drs/dr21xx.cpp =================================================================== --- clang/test/CXX/drs/dr21xx.cpp +++ clang/test/CXX/drs/dr21xx.cpp @@ -38,11 +38,11 @@ template<typename T> struct B { static const int n = 1; int f() { - return Y<n>::declared_later; // expected-error {{no member named 'declared_later'}} + return Y<n>::declared_later; // expected-error {{no member named 'declared_later'}} expected-note@-4 {{here}} } int g() { static const int n = 2; - return Y<n>::declared_later; // expected-error {{no member named 'declared_later'}} + return Y<n>::declared_later; // expected-error {{no member named 'declared_later'}} expected-note@-8 {{here}} } }; template<int N> struct Y<N> { Index: clang/test/CXX/drs/dr1xx.cpp =================================================================== --- clang/test/CXX/drs/dr1xx.cpp +++ clang/test/CXX/drs/dr1xx.cpp @@ -483,9 +483,9 @@ template<typename T> struct S { int n; }; struct A : S<int> { template<typename T> void f(); - template<typename T> struct S {}; + template<typename T> struct S {}; // expected-note {{declared here}} } a; - struct B : S<int> {} b; + struct B : S<int> {} b; // expected-note {{B' declared here}} void g() { a.f<int>(); (void)a.S<int>::n; // expected-error {{no member named 'n'}} Index: clang/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp =================================================================== --- clang/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp +++ clang/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp @@ -85,7 +85,7 @@ template <class T> struct B : A<T> { }; - template <class T> struct C { + template <class T> struct C { // expected-note {{declared here}} }; int test() { Index: clang/test/CXX/class.access/class.friend/p1.cpp =================================================================== --- clang/test/CXX/class.access/class.friend/p1.cpp +++ clang/test/CXX/class.access/class.friend/p1.cpp @@ -13,7 +13,7 @@ struct S { static void f(); }; // expected-note 2 {{'S' declared here}} S* g() { return 0; } // expected-note 2 {{'g' declared here}} -struct X { +struct X { // expected-note {{declared here}} friend struct S; friend S* g(); }; @@ -31,7 +31,7 @@ // Test that we recurse through namespaces to find already declared names, but // new names are declared within the enclosing namespace. namespace N { - struct X { + struct X { // expected-note 2 {{declared here}} friend struct S; friend S* g(); Index: clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp =================================================================== --- clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp +++ clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp @@ -86,7 +86,7 @@ template<typename T> T *end(T*); - class X { }; + class X { }; // expected-note {{X' declared here}} template <typename T> void Foo2() { T it1; Index: clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp =================================================================== --- clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp +++ clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp @@ -55,7 +55,7 @@ template<typename T> T *end(T*); - class X { }; + class X { }; // expected-note {{X' declared here}} template <typename T> void Foo2() { T it1; Index: clang/lib/Sema/SemaExprMember.cpp =================================================================== --- clang/lib/Sema/SemaExprMember.cpp +++ clang/lib/Sema/SemaExprMember.cpp @@ -713,6 +713,11 @@ << SS.getRange()); } else { SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << DC << BaseRange; + + if (Decl *D = dyn_cast<Decl>(DC)) { + if (!isa<TranslationUnitDecl>(D)) // Don't point at global namespace + SemaRef.Diag(D->getLocation(), diag::note_entity_declared_at) << DC << D->getLocation(); + } } }, [=](Sema &SemaRef, TypoExpr *TE, TypoCorrection TC) mutable { @@ -1024,6 +1029,12 @@ Diag(R.getNameLoc(), diag::err_no_member) << MemberName << DC << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()); + + if (Decl *D = dyn_cast<Decl>(DC)) { + if (!isa<TranslationUnitDecl>(D)) // Don't point at global namespace + Diag(D->getLocation(), diag::note_entity_declared_at) << DC << D->getLocation(); + } + return ExprError(); } Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -2110,10 +2110,15 @@ if (!TC) { // Emit a special diagnostic for failed member lookups. // FIXME: computing the declaration context might fail here (?) - if (Ctx) + if (Ctx) { SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << Ctx << SS.getRange(); - else + + if (Decl *D = dyn_cast<Decl>(Ctx)) { + if (!isa<TranslationUnitDecl>(D)) // Don't point at global namespace + SemaRef.Diag(D->getLocation(), diag::note_entity_declared_at) << Ctx << D->getLocation(); + } + } else SemaRef.Diag(TypoLoc, DiagnosticID) << Typo; return; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits