r193144 - Sema: Do not allow template declarations inside local classes

David Majnemer david.majnemer at gmail.com
Tue Oct 22 07:08:14 PDT 2013


Yep, looks like libcxxabi violates 14.5.2 [temp.mem]/p2. Looks like this
violation was introduced back in r184097. Note that trying to compile with
GCC gets us a similar error:
invalid declaration of member template in local class

CC'ing Howard Hinnant.


On Tue, Oct 22, 2013 at 4:36 AM, İsmail Dönmez <ismail at donmez.ws> wrote:

> This breaks libc++abi:
>
> [   52s] + clang++ -c -g -O3 -fPIC -std=c++11 -stdlib=libc++
> -fstrict-aliasing -Wstrict-aliasing=2 -Wsign-conversion -Wshadow
> -Wconversion -Wunused-variable -Wmissing-field-initializers
> -Wchar-subscripts -Wmismatched-tags -Wmissing-braces -Wshorten-64-to-32
> -Wsign-compare -Wstrict-aliasing=2 -Wstrict-overflow=4 -Wunused-parameter
> -Wnewline-eof -I../include ../src/cxa_demangle.cpp
> [   53s] ../src/cxa_demangle.cpp:4624:9: error: templates cannot be
> declared inside of a local class
> [   53s]         template <size_t N>
> [   53s]         ^~~~~~~~~~~~~~~~~~~
> [   53s] ../src/cxa_demangle.cpp:4631:8: error: no matching constructor
> for initialization of 'Db'
> [   53s]     Db db(a);
> [   53s]        ^  ~
> [   53s] ../src/cxa_demangle.cpp:4609:12: note: candidate constructor (the
> implicit move constructor) not viable: no known conversion from 'arena<bs>'
> to 'Db' for 1st argument
> [   53s]     struct Db
> [   53s]            ^
> [   53s] ../src/cxa_demangle.cpp:4609:12: note: candidate constructor (the
> implicit copy constructor) not viable: no known conversion from 'arena<bs>'
> to 'const Db' for 1st argument
> [   53s]     struct Db
> [   53s]            ^
> [   53s] ../src/cxa_demangle.cpp:4609:12: note: candidate constructor (the
> implicit default constructor) not viable: requires 0 arguments, but 1 was
> provided
>
>
> On Tue, Oct 22, 2013 at 7:14 AM, David Majnemer <david.majnemer at gmail.com>wrote:
>
>> Author: majnemer
>> Date: Mon Oct 21 23:14:18 2013
>> New Revision: 193144
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=193144&view=rev
>> Log:
>> Sema: Do not allow template declarations inside local classes
>>
>> Summary:
>> Enforce the rule in C++11 [temp.mem]p2 that local classes cannot have
>> member templates.
>>
>> This fixes PR16947.
>>
>> N.B.  C++14 has slightly different wording to afford generic lambdas
>> declared inside of functions.
>>
>> Fun fact:  Some formulations of local classes with member templates
>> would cause clang to crash during Itanium mangling, such as the
>> following:
>>
>> void outer_mem() {
>>   struct Inner {
>>     template <typename = void>
>>     struct InnerTemplateClass {
>>       static void itc_mem() {}
>>     };
>>   };
>>   Inner::InnerTemplateClass<>::itc_mem();
>> }
>>
>> Reviewers: eli.friedman, rsmith, doug.gregor, faisalv
>>
>> Reviewed By: doug.gregor
>>
>> CC: cfe-commits, ygao
>>
>> Differential Revision: http://llvm-reviews.chandlerc.com/D1866
>>
>> Added:
>>     cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p2.cpp
>> Removed:
>>     cfe/trunk/test/PCH/cxx-local-templates.cpp
>>     cfe/trunk/test/PCH/cxx1y-local-templates.cpp
>>     cfe/trunk/test/SemaTemplate/local-member-templates.cpp
>> Modified:
>>     cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>>     cfe/trunk/lib/Sema/SemaTemplate.cpp
>>     cfe/trunk/test/CodeGenCXX/mangle-local-class-names.cpp
>>     cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
>>
>> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=193144&r1=193143&r2=193144&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
>> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Oct 21
>> 23:14:18 2013
>> @@ -2835,6 +2835,8 @@ def warn_template_export_unsupported : W
>>    "exported templates are unsupported">;
>>  def err_template_outside_namespace_or_class_scope : Error<
>>    "templates can only be declared in namespace or class scope">;
>> +def err_template_inside_local_class : Error<
>> +  "templates cannot be declared inside of a local class">;
>>  def err_template_linkage : Error<"templates must have C++ linkage">;
>>  def err_template_typedef : Error<"a typedef cannot be a template">;
>>  def err_template_unnamed_class : Error<
>>
>> Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=193144&r1=193143&r2=193144&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Oct 21 23:14:18 2013
>> @@ -5459,8 +5459,20 @@ Sema::CheckTemplateDeclScope(Scope *S, T
>>    while (Ctx && isa<LinkageSpecDecl>(Ctx))
>>      Ctx = Ctx->getParent();
>>
>> -  if (Ctx && (Ctx->isFileContext() || Ctx->isRecord()))
>> -    return false;
>> +  if (Ctx) {
>> +    if (Ctx->isFileContext())
>> +      return false;
>> +    if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Ctx)) {
>> +      // C++ [temp.mem]p2:
>> +      //   A local class shall not have member templates.
>> +      if (RD->isLocalClass())
>> +        return Diag(TemplateParams->getTemplateLoc(),
>> +                    diag::err_template_inside_local_class)
>> +          << TemplateParams->getSourceRange();
>> +      else
>> +        return false;
>> +    }
>> +  }
>>
>>    return Diag(TemplateParams->getTemplateLoc(),
>>                diag::err_template_outside_namespace_or_class_scope)
>>
>> Added: cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p2.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p2.cpp?rev=193144&view=auto
>>
>> ==============================================================================
>> --- cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p2.cpp (added)
>> +++ cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p2.cpp Mon Oct 21
>> 23:14:18 2013
>> @@ -0,0 +1,12 @@
>> +// RUN: %clang_cc1 -fsyntax-only -verify %s
>> +
>> +template <typename>
>> +void quux();
>> +
>> +void fun() {
>> +  struct foo {
>> +    template <typename> struct bar {};  // expected-error{{templates
>> cannot be declared inside of a local class}}
>> +    template <typename> void baz() {}   // expected-error{{templates
>> cannot be declared inside of a local class}}
>> +    template <typename> void qux();     // expected-error{{templates
>> cannot be declared inside of a local class}}
>> +  };
>> +}
>>
>> Modified: cfe/trunk/test/CodeGenCXX/mangle-local-class-names.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-local-class-names.cpp?rev=193144&r1=193143&r2=193144&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/test/CodeGenCXX/mangle-local-class-names.cpp (original)
>> +++ cfe/trunk/test/CodeGenCXX/mangle-local-class-names.cpp Mon Oct 21
>> 23:14:18 2013
>> @@ -75,16 +75,6 @@ inline void OmittingCode(float x) {
>>  }
>>  void CallOmittingCode() { OmittingCode(1); }
>>
>> -// CHECK: @_ZZ25LocalTemplateFunctionTestdEN5Local3fooIdEET_S1_
>> -int LocalTemplateFunctionTest(double d) {
>> -  struct Local {
>> -    template<class T> T foo(T t) {
>> -      return t;
>> -    }
>> -  };
>> -  return Local().foo(d);
>> -}
>> -
>>  // CHECK: @_ZZ15LocalAnonStructvENUt0_1gEv
>>  inline void LocalAnonStruct() {
>>    if (0) {
>>
>> Removed: cfe/trunk/test/PCH/cxx-local-templates.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-local-templates.cpp?rev=193143&view=auto
>>
>> ==============================================================================
>> --- cfe/trunk/test/PCH/cxx-local-templates.cpp (original)
>> +++ cfe/trunk/test/PCH/cxx-local-templates.cpp (removed)
>> @@ -1,55 +0,0 @@
>> -// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t-cxx11
>> -// RUN: %clang_cc1 -ast-print -pedantic-errors -std=c++11 -include-pch
>> %t-cxx11  %s | FileCheck -check-prefix=CHECK-PRINT %s
>> -
>> -#ifndef HEADER_INCLUDED
>> -
>> -#define HEADER_INCLUDED
>> -
>> -int nontemplate_test(double d) {
>> -  struct Local {
>> -    template<class T> T foo(T t) {
>> -      return t;
>> -    }
>> -  };
>> -  return Local{}.foo(d);
>> -}
>> -
>> -template<class U>
>> -U template_test(U d) {
>> -  struct Local {
>> -    template<class T> T foo(T t) {
>> -      return t;
>> -    }
>> -  };
>> -  return Local{}.foo(d);
>> -}
>> -
>> -int nested_local() {
>> -  struct Inner1 {
>> -    int inner1_foo(char c) {
>> -      struct Inner2 {
>> -        template<class T> T inner2_foo(T t) {
>> -          return t;
>> -        }
>> -      };
>> -      return Inner2{}.inner2_foo(3.14);
>> -    }
>> -  };
>> -  return Inner1{}.inner1_foo('a');
>> -}
>> -
>> -#else
>> -
>> -// CHECK-PRINT: U template_test
>> -
>> -// CHECK-PRINT: int nontemplate_test(double)
>> -
>> -int nontemplate_test(double);
>> -
>> -template double template_test(double);
>> -int test2(int y) {
>> -  return nontemplate_test(y) + template_test(y);
>> -}
>> -
>> -
>> -#endif
>>
>> Removed: cfe/trunk/test/PCH/cxx1y-local-templates.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx1y-local-templates.cpp?rev=193143&view=auto
>>
>> ==============================================================================
>> --- cfe/trunk/test/PCH/cxx1y-local-templates.cpp (original)
>> +++ cfe/trunk/test/PCH/cxx1y-local-templates.cpp (removed)
>> @@ -1,58 +0,0 @@
>> -// RUN: %clang_cc1 -pedantic-errors -std=c++1y -emit-pch %s -o %t-cxx1y
>> -// RUN: %clang_cc1 -ast-print -pedantic-errors -std=c++1y -include-pch
>> %t-cxx1y  %s | FileCheck -check-prefix=CHECK-PRINT %s
>> -
>> -#ifndef HEADER_INCLUDED
>> -
>> -#define HEADER_INCLUDED
>> -
>> -auto nested_local_call_all() {
>> -  struct Inner1 {
>> -    auto inner1_foo(char c) {
>> -      struct Inner2 {
>> -        template<class T> T inner2_foo(T t) {
>> -          return t;
>> -        }
>> -      };
>> -      return Inner2{};
>> -    }
>> -  };
>> -  return Inner1{}.inner1_foo('a').inner2_foo(4);
>> -}
>> -
>> -
>> -auto nested_local() {
>> -  struct Inner1 {
>> -    auto inner1_foo(char c) {
>> -      struct Inner2 {
>> -        template<class T> T inner2_foo(T t) {
>> -          return t;
>> -        }
>> -      };
>> -      return Inner2{};
>> -    }
>> -  };
>> -  return Inner1{};
>> -}
>> -
>> -
>> -int test() {
>> -  auto A = nested_local_call_all();
>> -  auto B = nested_local();
>> -  auto C = B.inner1_foo('a');
>> -  C.inner2_foo(3.14);
>> -
>> -}
>> -
>> -
>> -#else
>> -
>> -// CHECK-PRINT: int nested_local_call_all
>> -// CHECK-PRINT: nested_local
>> -auto nested_local_call_all();
>> -
>> -int test(int y) {
>> -  return nested_local_call_all();
>> -}
>> -
>> -
>> -#endif
>>
>> Modified: cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp?rev=193144&r1=193143&r2=193144&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
>> (original)
>> +++ cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp Mon
>> Oct 21 23:14:18 2013
>> @@ -44,13 +44,14 @@ namespace dr1330_example {
>>      A<int>().f(42);
>>    }
>>
>> +  struct S {
>> +    template<typename T>
>> +    static int f() noexcept(noexcept(A<T>().f("boo!"))) { return 0; } //
>> \
>> +    // expected-note {{instantiation of exception spec}}
>> +    typedef decltype(f<S>()) X;
>> +  };
>> +
>>    int test2() {
>> -    struct S {
>> -      template<typename T>
>> -      static int f() noexcept(noexcept(A<T>().f("boo!"))) { return 0; }
>> // \
>> -      // expected-note {{instantiation of exception spec}}
>> -      typedef decltype(f<S>()) X;
>> -    };
>>      S().f<S>(); // ok
>>      S().f<int>(); // expected-note {{instantiation of exception spec}}
>>    }
>>
>> Removed: cfe/trunk/test/SemaTemplate/local-member-templates.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/local-member-templates.cpp?rev=193143&view=auto
>>
>> ==============================================================================
>> --- cfe/trunk/test/SemaTemplate/local-member-templates.cpp (original)
>> +++ cfe/trunk/test/SemaTemplate/local-member-templates.cpp (removed)
>> @@ -1,99 +0,0 @@
>> -// RUN: %clang_cc1 -std=c++1y -verify %s
>> -// RUN: %clang_cc1 -std=c++1y -verify %s -fdelayed-template-parsing
>> -
>> -namespace nested_local_templates_1 {
>> -
>> -template <class T> struct Outer {
>> -  template <class U> int outer_mem(T t, U u) {
>> -    struct Inner {
>> -      template <class V> int inner_mem(T t, U u, V v) {
>> -        struct InnerInner {
>> -          template <class W> int inner_inner_mem(W w, T t, U u, V v) {
>> -            return 0;
>> -          }
>> -        };
>> -        InnerInner().inner_inner_mem("abc", t, u, v);
>> -        return 0;
>> -      }
>> -    };
>> -    Inner i;
>> -    i.inner_mem(t, u, 3.14);
>> -    return 0;
>> -  }
>> -
>> -  template <class U> int outer_mem(T t, U *u);
>> -};
>> -
>> -template int Outer<int>::outer_mem(int, char);
>> -
>> -template <class T> template <class U> int Outer<T>::outer_mem(T t, U *u)
>> {
>> -  struct Inner {
>> -    template <class V>
>> -    int inner_mem(T t, U u, V v) { //expected-note{{candidate function}}
>> -      struct InnerInner {
>> -        template <class W> int inner_inner_mem(W w, T t, U u, V v) {
>> return 0; }
>> -      };
>> -      InnerInner().inner_inner_mem("abc", t, u, v);
>> -      return 0;
>> -    }
>> -  };
>> -  Inner i;
>> -  i.inner_mem(t, U{}, i);
>> -  i.inner_mem(t, u, 3.14); //expected-error{{no matching member function
>> for call to 'inner}}
>> -  return 0;
>> -}
>> -
>> -template int Outer<int>::outer_mem(int, char *); //expected-note{{in
>> instantiation of function}}
>> -
>> -} // end ns
>> -
>> -namespace nested_local_templates_2 {
>> -
>> -template <class T> struct Outer {
>> -  template <class U> void outer_mem(T t, U u) {
>> -    struct Inner {
>> -      template <class V> struct InnerTemplateClass {
>> -        template <class W>
>> -        void itc_mem(T t, U u, V v, W w) { //expected-note{{candidate
>> function}}
>> -          struct InnerInnerInner {
>> -            template <class X> void iii_mem(X x) {}
>> -          };
>> -          InnerInnerInner i;
>> -          i.iii_mem("abc");
>> -        }
>> -      };
>> -    };
>> -    Inner i;
>> -    typename Inner::template InnerTemplateClass<Inner> ii;
>> -    ii.itc_mem(t, u, i, "jim");
>> -    ii.itc_mem(t, u, 0, "abd"); //expected-error{{no matching member
>> function}}
>> -  }
>> -};
>> -
>> -template void
>> -Outer<int>::outer_mem(int, char); //expected-note{{in instantiation of}}
>> -
>> -}
>> -
>> -namespace more_nested_local_templates {
>> -
>> -int test() {
>> -  struct Local {
>> -    template<class U> void foo(U u) {
>> -      struct Inner {
>> -        template<class A>
>> -        auto operator()(A a, U u2) -> U {
>> -          return u2;
>> -        };
>> -      };
>> -      Inner GL;
>> -      GL('a', u );
>> -      GL(3.14, u );
>> -    }
>> -  };
>> -  Local l;
>> -  l.foo("nmabc");
>> -  return 0;
>> -}
>> -int t = test();
>> -}
>> \ No newline at end of file
>>
>>
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131022/f8a636e1/attachment.html>


More information about the cfe-commits mailing list