summaryrefslogtreecommitdiff
path: root/test/SemaTemplate/ms-lookup-template-base-classes.cpp
diff options
context:
space:
mode:
authorReid Kleckner <reid@kleckner.net>2014-07-08 20:05:48 +0000
committerReid Kleckner <reid@kleckner.net>2014-07-08 20:05:48 +0000
commit3df7e8ef65f609d3475b15569b087ba0fff3f6ee (patch)
tree57058b80904c72dd4300b17b61d35c1d8f5b1ab7 /test/SemaTemplate/ms-lookup-template-base-classes.cpp
parent9ed6e682654fdb787d58a3f070cb6cbaaafbe89b (diff)
downloadclang-3df7e8ef65f609d3475b15569b087ba0fff3f6ee.tar.gz
Allow more lookup of types in dependent base classes
MSVC appears to perform name lookup into dependent base classes when the dependent base class has a known primary template. This allows them to know whether some unqualified ids are types or not, which allows them to parse more class templates without typename keywords. We can do the same thing when type name lookup fails, and if we find a single type decl in one of our dependent base classes, recover as though the user wrote 'typename MyClass::TypeFromBase'. This allows us to parse some COM smart pointer classes in wrl/client.h from the Windows 8 SDK. Reviewers: rsmith Differential Revision: http://reviews.llvm.org/D4237 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@212561 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.cpp183
1 files changed, 182 insertions, 1 deletions
diff --git a/test/SemaTemplate/ms-lookup-template-base-classes.cpp b/test/SemaTemplate/ms-lookup-template-base-classes.cpp
index 434039500c..635f0b0cd0 100644
--- a/test/SemaTemplate/ms-lookup-template-base-classes.cpp
+++ b/test/SemaTemplate/ms-lookup-template-base-classes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -fms-compatibility -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++1y -fms-compatibility -fsyntax-only -verify %s
template <class T>
@@ -275,3 +275,184 @@ template <typename T> struct Derived : Base<T> {
};
template struct Derived<int>;
}
+
+namespace typedef_in_base {
+template <typename T> struct A { typedef T NameFromBase; };
+template <typename T> struct B : A<T> {
+ NameFromBase m; // expected-warning {{found via unqualified lookup into dependent bases}}
+};
+static_assert(sizeof(B<int>) == 4, "");
+}
+
+namespace struct_in_base {
+template <typename T> struct A { struct NameFromBase {}; };
+template <typename T> struct B : A<T> {
+ NameFromBase m; // expected-warning {{found via unqualified lookup into dependent bases}}
+};
+static_assert(sizeof(B<int>) == 1, "");
+}
+
+namespace enum_in_base {
+template <typename T> struct A { enum NameFromBase { X }; };
+template <typename T> struct B : A<T> {
+ NameFromBase m; // expected-warning {{found via unqualified lookup into dependent bases}}
+};
+static_assert(sizeof(B<int>) == sizeof(A<int>::NameFromBase), "");
+}
+
+namespace two_types_in_base {
+template <typename T> struct A { typedef T NameFromBase; };
+template <typename T> struct B { struct NameFromBase { T m; }; };
+template <typename T> struct C : A<T>, B<T> {
+ NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}}
+};
+static_assert(sizeof(C<int>) == 4, "");
+}
+
+namespace type_and_decl_in_base {
+template <typename T> struct A { typedef T NameFromBase; };
+template <typename T> struct B { static const T NameFromBase = 42; };
+template <typename T> struct C : A<T>, B<T> {
+ NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}}
+};
+}
+
+namespace classify_type_from_base {
+template <typename T> struct A { struct NameFromBase {}; };
+template <typename T> struct B : A<T> {
+ A<NameFromBase> m; // expected-warning {{found via unqualified lookup into dependent bases}}
+};
+}
+
+namespace classify_nontype_from_base {
+// MSVC does not do lookup of non-type declarations from dependent template base
+// classes. The extra lookup only applies to types.
+template <typename T> struct A { void NameFromBase() {} };
+template <void (*F)()> struct B { };
+template <typename T> struct C : A<T> {
+ B<C::NameFromBase> a; // correct
+ B<NameFromBase> b; // expected-error {{use of undeclared identifier 'NameFromBase'}}
+};
+}
+
+namespace template_in_base {
+template <typename T> struct A {
+ template <typename U> struct NameFromBase { U x; };
+};
+template <typename T> struct B : A<T> {
+ // Correct form.
+ typename B::template NameFromBase<T> m;
+};
+template <typename T> struct C : A<T> {
+ // Incorrect form.
+ NameFromBase<T> m; // expected-error {{unknown type name 'NameFromBase'}}
+ //expected-error@-1 {{expected member name or ';' after declaration specifiers}}
+};
+}
+
+namespace type_in_inner_class_in_base {
+template <typename T>
+struct A {
+ struct B { typedef T NameFromBase; };
+};
+template <typename T>
+struct C : A<T>::B { NameFromBase m; }; // expected-error {{unknown type name 'NameFromBase'}}
+}
+
+namespace type_in_inner_template_class_in_base {
+template <typename T>
+struct A {
+ template <typename U> struct B { typedef U InnerType; };
+};
+template <typename T>
+struct C : A<T>::template B<T> {
+ NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}}
+};
+}
+
+namespace have_nondependent_base {
+template <typename T>
+struct A {
+ // Nothing, lookup should fail.
+};
+template <typename T>
+struct B : A<T> { NameFromBase m; }; // expected-error {{unknown type name 'NameFromBase'}}
+struct C : A<int> { NameFromBase m; }; // expected-error {{unknown type name 'NameFromBase'}}
+}
+
+namespace lookup_in_function_contexts {
+template <typename T> struct A { typedef T NameFromBase; };
+template <typename T>
+struct B : A<T> {
+ // expected-warning@+1 {{lookup into dependent bases}}
+ static auto lateSpecifiedFunc() -> decltype(NameFromBase()) {
+ return {};
+ }
+
+ // FIXME: MSVC accepts all of the code below that isn't C++14 only. Downgrade
+ // these errors to warnings.
+
+ static void memberFunc() {
+ NameFromBase x; // expected-error {{unknown type name 'NameFromBase'}}
+ }
+
+ static void funcLocalClass() {
+ struct X {
+ NameFromBase x; // expected-error {{unknown type name 'NameFromBase'}}
+ } y;
+ }
+
+ void localClassMethod() {
+ struct X {
+ void bar() {
+ NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}}
+ }
+ } x;
+ x.bar();
+ }
+
+ static void funcLambda() {
+ auto l = []() {
+ NameFromBase x; // expected-error {{unknown type name 'NameFromBase'}}
+ };
+ l();
+ }
+
+ static constexpr int constexprFunc() {
+ NameFromBase x = {}; // expected-error {{unknown type name 'NameFromBase'}}
+ // FIXME: Suppress this diagnostic, we have an initializer.
+ // expected-error@-2 {{variables defined in a constexpr function must be initialized}}
+ return sizeof(x);
+ }
+
+ static auto autoFunc() {
+ NameFromBase x; // expected-error {{unknown type name 'NameFromBase'}}
+ return x;
+ }
+};
+
+// Force us to parse the methods.
+template struct B<int>;
+}
+
+namespace function_template_deduction {
+// Overloaded function templates.
+template <int N> int f() { return N; }
+template <typename T> int f() { return sizeof(T); }
+
+// Dependent base class with type.
+template <typename T>
+struct A { typedef T NameFromBase; };
+template <typename T>
+struct B : A<T> {
+ // expected-warning@+1 {{found via unqualified lookup into dependent bases}}
+ int x = f<NameFromBase>();
+};
+
+// Dependent base class with enum.
+template <typename T> struct C { enum { NameFromBase = 4 }; };
+template <typename T> struct D : C<T> {
+ // expected-warning@+1 {{use of undeclared identifier 'NameFromBase'; unqualified lookup into dependent bases}}
+ int x = f<NameFromBase>();
+};
+}