r230301 - [modules] Ensure we've imported all declarations of a template before

Richard Smith richard-llvm at metafoo.co.uk
Mon Feb 23 18:44:23 PST 2015


Author: rsmith
Date: Mon Feb 23 20:44:23 2015
New Revision: 230301

URL: http://llvm.org/viewvc/llvm-project?rev=230301&view=rev
Log:
[modules] Ensure we've imported all declarations of a template before
attempting to lazily deserialize its specializations; otherwise, there might be
pending specializations that we don't know about yet.

Added:
    cfe/trunk/test/Modules/Inputs/redecl-templates/
    cfe/trunk/test/Modules/Inputs/redecl-templates/a.h
    cfe/trunk/test/Modules/Inputs/redecl-templates/module.modulemap
    cfe/trunk/test/Modules/redecl-templates.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/lib/AST/DeclTemplate.cpp

Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=230301&r1=230300&r2=230301&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Mon Feb 23 20:44:23 2015
@@ -835,6 +835,15 @@ public:
        static_cast<const RedeclarableTemplateDecl *>(this)->getPreviousDecl());
   }
 
+  FunctionTemplateDecl *getMostRecentDecl() {
+    return cast<FunctionTemplateDecl>(
+        static_cast<RedeclarableTemplateDecl *>(this)
+            ->getMostRecentDecl());
+  }
+  const FunctionTemplateDecl *getMostRecentDecl() const {
+    return const_cast<FunctionTemplateDecl*>(this)->getMostRecentDecl();
+  }
+
   FunctionTemplateDecl *getInstantiatedFromMemberTemplate() {
     return cast_or_null<FunctionTemplateDecl>(
              RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());
@@ -2731,6 +2740,14 @@ public:
               this)->getPreviousDecl());
   }
 
+  VarTemplateDecl *getMostRecentDecl() {
+    return cast<VarTemplateDecl>(
+        static_cast<RedeclarableTemplateDecl *>(this)->getMostRecentDecl());
+  }
+  const VarTemplateDecl *getMostRecentDecl() const {
+    return const_cast<VarTemplateDecl *>(this)->getMostRecentDecl();
+  }
+
   VarTemplateDecl *getInstantiatedFromMemberTemplate() {
     return cast_or_null<VarTemplateDecl>(
         RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());

Modified: cfe/trunk/lib/AST/DeclTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=230301&r1=230300&r2=230301&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclTemplate.cpp (original)
+++ cfe/trunk/lib/AST/DeclTemplate.cpp Mon Feb 23 20:44:23 2015
@@ -272,7 +272,11 @@ FunctionTemplateDecl::newCommon(ASTConte
 }
 
 void FunctionTemplateDecl::LoadLazySpecializations() const {
-  Common *CommonPtr = getCommonPtr();
+  // Grab the most recent declaration to ensure we've loaded any lazy
+  // redeclarations of this template.
+  //
+  // FIXME: Avoid walking the entire redeclaration chain here.
+  Common *CommonPtr = getMostRecentDecl()->getCommonPtr();
   if (CommonPtr->LazySpecializations) {
     ASTContext &Context = getASTContext();
     uint32_t *Specs = CommonPtr->LazySpecializations;
@@ -342,7 +346,11 @@ ClassTemplateDecl *ClassTemplateDecl::Cr
 }
 
 void ClassTemplateDecl::LoadLazySpecializations() const {
-  Common *CommonPtr = getCommonPtr();
+  // Grab the most recent declaration to ensure we've loaded any lazy
+  // redeclarations of this template.
+  //
+  // FIXME: Avoid walking the entire redeclaration chain here.
+  Common *CommonPtr = getMostRecentDecl()->getCommonPtr();
   if (CommonPtr->LazySpecializations) {
     ASTContext &Context = getASTContext();
     uint32_t *Specs = CommonPtr->LazySpecializations;
@@ -966,7 +974,11 @@ VarTemplateDecl *VarTemplateDecl::Create
 // TODO: Unify across class, function and variable templates?
 //       May require moving this and Common to RedeclarableTemplateDecl.
 void VarTemplateDecl::LoadLazySpecializations() const {
-  Common *CommonPtr = getCommonPtr();
+  // Grab the most recent declaration to ensure we've loaded any lazy
+  // redeclarations of this template.
+  //
+  // FIXME: Avoid walking the entire redeclaration chain here.
+  Common *CommonPtr = getMostRecentDecl()->getCommonPtr();
   if (CommonPtr->LazySpecializations) {
     ASTContext &Context = getASTContext();
     uint32_t *Specs = CommonPtr->LazySpecializations;

Added: cfe/trunk/test/Modules/Inputs/redecl-templates/a.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/redecl-templates/a.h?rev=230301&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/redecl-templates/a.h (added)
+++ cfe/trunk/test/Modules/Inputs/redecl-templates/a.h Mon Feb 23 20:44:23 2015
@@ -0,0 +1,8 @@
+template<int N> struct A;
+template<> struct A<1>;
+
+template<int N> constexpr void f();
+template<> constexpr void f<1>();
+
+template<int N> extern int v;
+template<> extern int v<1>;

Added: cfe/trunk/test/Modules/Inputs/redecl-templates/module.modulemap
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/redecl-templates/module.modulemap?rev=230301&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/redecl-templates/module.modulemap (added)
+++ cfe/trunk/test/Modules/Inputs/redecl-templates/module.modulemap Mon Feb 23 20:44:23 2015
@@ -0,0 +1 @@
+module A { header "a.h" }

Added: cfe/trunk/test/Modules/redecl-templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/redecl-templates.cpp?rev=230301&view=auto
==============================================================================
--- cfe/trunk/test/Modules/redecl-templates.cpp (added)
+++ cfe/trunk/test/Modules/redecl-templates.cpp Mon Feb 23 20:44:23 2015
@@ -0,0 +1,32 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x c++ -I %S/Inputs/redecl-templates %s -verify -std=c++14
+// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs/redecl-templates %s -verify -std=c++14
+// expected-no-diagnostics
+
+template<int N> struct A {};
+template<int N> using X = A<N>;
+
+template<int N> constexpr void f() {}
+template<int N> constexpr void g() { f<N>(); }
+
+template<int N> extern int v;
+template<int N> int &w = v<N>;
+
+#include "a.h"
+
+// Be careful not to mention A here, that'll import the decls from "a.h".
+int g(X<1> *);
+X<1> *p = 0;
+
+// This will implicitly instantiate A<1> if we haven't imported the explicit
+// specialization declaration from "a.h".
+int k = g(p);
+// Likewise for f and v.
+void h() { g<1>(); }
+int &x = w<1>;
+
+// This is OK: we declared the explicit specialization before we triggered
+// instantiation of this specialization.
+template<> struct A<1> {};
+template<> constexpr void f<1>() {}
+template<> int v<1>;





More information about the cfe-commits mailing list