arphaman created this revision.
arphaman added reviewers: rjmccall, rsmith.
arphaman added a subscriber: cfe-commits.
arphaman set the repository for this revision to rL LLVM.

This patch fixes a NULL pointer crash that happens when clang is trying to 
create an implicit default constructor for a specialization of a record 
template which is defined in a specialization of a parent record template and 
has a field declaration with an initializer expression.

The following piece of code reproduces this problem:

  template<typename T>
  class A {
  public:
    template<int i> 
    struct Inner;
  };
  
  template<>
  template<int i>
  struct A<int>::Inner {
    int member = 42;
  };
  
  int main(void) {
    return A<int>::Inner<0>().member;
  }

The crash happens because `CXXRecordDecl::getTemplateInstantiationPattern` 
returns nil when instantiating `A<int>::Inner<0>`, because it tries to get the 
instantiation pattern from the declaration of `Inner` (which has no definition 
and thus no instantiation pattern), rather than the specialized definition of 
`Inner`. This patch fixes this by making sure that the instantiation pattern 
comes from the definition rather than the declaration of the record template.


Repository:
  rL LLVM

https://reviews.llvm.org/D25942

Files:
  lib/AST/DeclCXX.cpp
  test/CodeGenCXX/cxx11-crashes.cpp


Index: test/CodeGenCXX/cxx11-crashes.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/cxx11-crashes.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 %s -o - | 
FileCheck %s
+
+namespace rd28886662 {
+
+template<typename T>
+class A {
+public:
+  template<int i>
+  struct Inner;
+};
+
+template<>
+template<int i>
+struct A<int>::Inner {
+  int member = 42; // should be ok
+};
+
+int foo(void) {
+  return A<int>::Inner<0>().member;
+}
+
+// CHECK: _ZN10rd288866621AIiE5InnerILi0EEC2Ev
+// CHECK: store i32 42, i32* %member
+
+}
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -1347,7 +1347,8 @@
     auto From = TD->getInstantiatedFrom();
     if (auto *CTD = From.dyn_cast<ClassTemplateDecl *>()) {
       while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) {
-        if (NewCTD->isMemberSpecialization())
+        if (NewCTD->isMemberSpecialization() ||
+            !NewCTD->isThisDeclarationADefinition())
           break;
         CTD = NewCTD;
       }


Index: test/CodeGenCXX/cxx11-crashes.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/cxx11-crashes.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 %s -o - | FileCheck %s
+
+namespace rd28886662 {
+
+template<typename T>
+class A {
+public:
+  template<int i>
+  struct Inner;
+};
+
+template<>
+template<int i>
+struct A<int>::Inner {
+  int member = 42; // should be ok
+};
+
+int foo(void) {
+  return A<int>::Inner<0>().member;
+}
+
+// CHECK: _ZN10rd288866621AIiE5InnerILi0EEC2Ev
+// CHECK: store i32 42, i32* %member
+
+}
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -1347,7 +1347,8 @@
     auto From = TD->getInstantiatedFrom();
     if (auto *CTD = From.dyn_cast<ClassTemplateDecl *>()) {
       while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) {
-        if (NewCTD->isMemberSpecialization())
+        if (NewCTD->isMemberSpecialization() ||
+            !NewCTD->isThisDeclarationADefinition())
           break;
         CTD = NewCTD;
       }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to