Consider code like the following: ``` #include <memory>
template <class T> class MyAllocator : public std::allocator<T> { public: typedef std::allocator<T> Alloc; typedef typename Alloc::pointer pointer; typedef typename Alloc::size_type size_type; MyAllocator() {} template <typename U> MyAllocator(const MyAllocator<U>& x) : Alloc(x) {} pointer allocate(size_type n, std::allocator<void>::const_pointer /*hint*/ = nullptr) { void* p = malloc(n * sizeof(T)); return static_cast<pointer>(p); } void deallocate(pointer p, size_type) { free(p); } template <typename U> struct rebind { typedef MyAllocator<U> other; }; private: template <class U> friend class MyAllocator; }; std::shared_ptr<int> x = std::allocate_shared<int>(MyAllocator<int>(), 0); ``` This will fail to compile against libstdc++ 4.9's alloc_traits.h, when that header comes from a module, with an error message along the lines of: .../bits/alloc_traits.h:197:2: error: too few template arguments for class template '__alloctr_rebind' using rebind_alloc = typename __alloctr_rebind<_Alloc, _Tp>::__type; I think this is enough for you to debug, but let me know if not. I'm going to revert this temporarily to unbreak our modules builds using this version of libstdc++. On Tue, Apr 18, 2017 at 8:14 PM Chandler Carruth <chandl...@google.com> wrote: > This appears to break a pretty straightforward use of things like > libstdc++'s __alloctr_rebind (undefined template with a default argument, > specializations, etc): > > https://github.com/gcc-mirror/gcc/blob/gcc-4_9-branch/libstdc++-v3/include/bits/alloc_traits.h#L58-L73 > > At least, I'm getting errors from this. I'm working on a test case, but as > usual, the test case may be... large. > > On Tue, Apr 18, 2017 at 6:49 PM Richard Smith via cfe-commits < > cfe-commits@lists.llvm.org> wrote: > >> Author: rsmith >> Date: Tue Apr 18 20:36:43 2017 >> New Revision: 300650 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=300650&view=rev >> Log: >> [modules] Properly look up the owning module for an instantiation of a >> merged template. >> >> When looking for the template instantiation pattern of a templated entity, >> consistently select the definition of the pattern if there is one. This >> means >> we'll pick the same owning module when we start instantiating a template >> that >> we'll later pick when determining which modules are visible during that >> instantiation. >> >> Modified: >> cfe/trunk/lib/AST/Decl.cpp >> cfe/trunk/lib/AST/DeclCXX.cpp >> cfe/trunk/lib/Sema/SemaLookup.cpp >> cfe/trunk/test/Modules/Inputs/template-default-args/a.h >> cfe/trunk/test/Modules/template-default-args.cpp >> >> Modified: cfe/trunk/lib/AST/Decl.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=300650&r1=300649&r2=300650&view=diff >> >> ============================================================================== >> --- cfe/trunk/lib/AST/Decl.cpp (original) >> +++ cfe/trunk/lib/AST/Decl.cpp Tue Apr 18 20:36:43 2017 >> @@ -2251,6 +2251,13 @@ bool VarDecl::checkInitIsICE() const { >> return Eval->IsICE; >> } >> >> +template<typename DeclT> >> +static DeclT *getDefinitionOrSelf(DeclT *D) { >> + if (auto *Def = D->getDefinition()) >> + return Def; >> + return D; >> +} >> + >> VarDecl *VarDecl::getTemplateInstantiationPattern() const { >> // If it's a variable template specialization, find the template or >> partial >> // specialization from which it was instantiated. >> @@ -2262,7 +2269,7 @@ VarDecl *VarDecl::getTemplateInstantiati >> break; >> VTD = NewVTD; >> } >> - return VTD->getTemplatedDecl()->getDefinition(); >> + return getDefinitionOrSelf(VTD->getTemplatedDecl()); >> } >> if (auto *VTPSD = >> From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) { >> @@ -2271,7 +2278,7 @@ VarDecl *VarDecl::getTemplateInstantiati >> break; >> VTPSD = NewVTPSD; >> } >> - return VTPSD->getDefinition(); >> + return getDefinitionOrSelf<VarDecl>(VTPSD); >> } >> } >> >> @@ -2280,23 +2287,18 @@ VarDecl *VarDecl::getTemplateInstantiati >> VarDecl *VD = getInstantiatedFromStaticDataMember(); >> while (auto *NewVD = VD->getInstantiatedFromStaticDataMember()) >> VD = NewVD; >> - return VD->getDefinition(); >> + return getDefinitionOrSelf(VD); >> } >> } >> >> if (VarTemplateDecl *VarTemplate = getDescribedVarTemplate()) { >> - >> while (VarTemplate->getInstantiatedFromMemberTemplate()) { >> if (VarTemplate->isMemberSpecialization()) >> break; >> VarTemplate = VarTemplate->getInstantiatedFromMemberTemplate(); >> } >> >> - assert((!VarTemplate->getTemplatedDecl() || >> - !isTemplateInstantiation(getTemplateSpecializationKind())) && >> - "couldn't find pattern for variable instantiation"); >> - >> - return VarTemplate->getTemplatedDecl(); >> + return getDefinitionOrSelf(VarTemplate->getTemplatedDecl()); >> } >> return nullptr; >> } >> @@ -3201,7 +3203,7 @@ bool FunctionDecl::isTemplateInstantiati >> FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const { >> // Handle class scope explicit specialization special case. >> if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization) >> - return getClassScopeSpecializationPattern(); >> + return getDefinitionOrSelf(getClassScopeSpecializationPattern()); >> >> // If this is a generic lambda call operator specialization, its >> // instantiation pattern is always its primary template's pattern >> @@ -3214,16 +3216,10 @@ FunctionDecl *FunctionDecl::getTemplateI >> >> if (isGenericLambdaCallOperatorSpecialization( >> dyn_cast<CXXMethodDecl>(this))) { >> - assert(getPrimaryTemplate() && "A generic lambda specialization must >> be " >> - "generated from a primary call >> operator " >> - "template"); >> - assert(getPrimaryTemplate()->getTemplatedDecl()->getBody() && >> - "A generic lambda call operator template must always have a >> body - " >> - "even if instantiated from a prototype (i.e. as written) >> member " >> - "template"); >> - return getPrimaryTemplate()->getTemplatedDecl(); >> + assert(getPrimaryTemplate() && "not a generic lambda call >> operator?"); >> + return getDefinitionOrSelf(getPrimaryTemplate()->getTemplatedDecl()); >> } >> - >> + >> if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) { >> while (Primary->getInstantiatedFromMemberTemplate()) { >> // If we have hit a point where the user provided a specialization >> of >> @@ -3232,11 +3228,14 @@ FunctionDecl *FunctionDecl::getTemplateI >> break; >> Primary = Primary->getInstantiatedFromMemberTemplate(); >> } >> - >> - return Primary->getTemplatedDecl(); >> + >> + return getDefinitionOrSelf(Primary->getTemplatedDecl()); >> } >> - >> - return getInstantiatedFromMemberFunction(); >> + >> + if (auto *MFD = getInstantiatedFromMemberFunction()) >> + return getDefinitionOrSelf(MFD); >> + >> + return nullptr; >> } >> >> FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const { >> @@ -3780,7 +3779,7 @@ EnumDecl *EnumDecl::getTemplateInstantia >> EnumDecl *ED = getInstantiatedFromMemberEnum(); >> while (auto *NewED = ED->getInstantiatedFromMemberEnum()) >> ED = NewED; >> - return ED; >> + return getDefinitionOrSelf(ED); >> } >> } >> >> >> Modified: cfe/trunk/lib/AST/DeclCXX.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=300650&r1=300649&r2=300650&view=diff >> >> ============================================================================== >> --- cfe/trunk/lib/AST/DeclCXX.cpp (original) >> +++ cfe/trunk/lib/AST/DeclCXX.cpp Tue Apr 18 20:36:43 2017 >> @@ -1364,6 +1364,13 @@ CXXRecordDecl::setTemplateSpecialization >> } >> >> const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() >> const { >> + auto GetDefinitionOrSelf = >> + [](const CXXRecordDecl *D) -> const CXXRecordDecl * { >> + if (auto *Def = D->getDefinition()) >> + return Def; >> + return D; >> + }; >> + >> // If it's a class template specialization, find the template or >> partial >> // specialization from which it was instantiated. >> if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(this)) { >> @@ -1374,7 +1381,7 @@ const CXXRecordDecl *CXXRecordDecl::getT >> break; >> CTD = NewCTD; >> } >> - return CTD->getTemplatedDecl()->getDefinition(); >> + return GetDefinitionOrSelf(CTD->getTemplatedDecl()); >> } >> if (auto *CTPSD = >> From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) { >> @@ -1383,7 +1390,7 @@ const CXXRecordDecl *CXXRecordDecl::getT >> break; >> CTPSD = NewCTPSD; >> } >> - return CTPSD->getDefinition(); >> + return GetDefinitionOrSelf(CTPSD); >> } >> } >> >> @@ -1392,7 +1399,7 @@ const CXXRecordDecl *CXXRecordDecl::getT >> const CXXRecordDecl *RD = this; >> while (auto *NewRD = RD->getInstantiatedFromMemberClass()) >> RD = NewRD; >> - return RD->getDefinition(); >> + return GetDefinitionOrSelf(RD); >> } >> } >> >> >> Modified: cfe/trunk/lib/Sema/SemaLookup.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=300650&r1=300649&r2=300650&view=diff >> >> ============================================================================== >> --- cfe/trunk/lib/Sema/SemaLookup.cpp (original) >> +++ cfe/trunk/lib/Sema/SemaLookup.cpp Tue Apr 18 20:36:43 2017 >> @@ -1326,12 +1326,6 @@ bool Sema::CppLookupName(LookupResult &R >> return !R.empty(); >> } >> >> -/// \brief Find the declaration that a class temploid member >> specialization was >> -/// instantiated from, or the member itself if it is an explicit >> specialization. >> -static Decl *getInstantiatedFrom(Decl *D, MemberSpecializationInfo >> *MSInfo) { >> - return MSInfo->isExplicitSpecialization() ? D : >> MSInfo->getInstantiatedFrom(); >> -} >> - >> Module *Sema::getOwningModule(Decl *Entity) { >> // If it's imported, grab its owning module. >> Module *M = Entity->getImportedOwningModule(); >> @@ -1413,20 +1407,14 @@ static Module *getDefiningModule(Sema &S >> if (CXXRecordDecl *Pattern = RD->getTemplateInstantiationPattern()) >> Entity = Pattern; >> } else if (EnumDecl *ED = dyn_cast<EnumDecl>(Entity)) { >> - if (MemberSpecializationInfo *MSInfo = >> ED->getMemberSpecializationInfo()) >> - Entity = getInstantiatedFrom(ED, MSInfo); >> + if (auto *Pattern = ED->getTemplateInstantiationPattern()) >> + Entity = Pattern; >> } else if (VarDecl *VD = dyn_cast<VarDecl>(Entity)) { >> - // FIXME: Map from variable template specializations back to the >> template. >> - if (MemberSpecializationInfo *MSInfo = >> VD->getMemberSpecializationInfo()) >> - Entity = getInstantiatedFrom(VD, MSInfo); >> + if (VarDecl *Pattern = VD->getTemplateInstantiationPattern()) >> + Entity = Pattern; >> } >> >> - // Walk up to the containing context. That might also have been >> instantiated >> - // from a template. >> - DeclContext *Context = Entity->getDeclContext(); >> - if (Context->isFileContext()) >> - return S.getOwningModule(Entity); >> - return getDefiningModule(S, cast<Decl>(Context)); >> + return S.getOwningModule(Entity); >> } >> >> llvm::DenseSet<Module*> &Sema::getLookupModules() { >> >> Modified: cfe/trunk/test/Modules/Inputs/template-default-args/a.h >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/template-default-args/a.h?rev=300650&r1=300649&r2=300650&view=diff >> >> ============================================================================== >> --- cfe/trunk/test/Modules/Inputs/template-default-args/a.h (original) >> +++ cfe/trunk/test/Modules/Inputs/template-default-args/a.h Tue Apr 18 >> 20:36:43 2017 >> @@ -14,3 +14,11 @@ struct FriendL { >> template<typename T> friend struct L; >> }; >> END >> + >> +namespace DeferredLookup { >> + template<typename T, typename U = T> using X = U; >> + template<typename T> void f() { (void) X<T>(); } >> + template<typename T> int n = X<T>(); >> + template<typename T> struct S { X<T> xt; enum E : int; }; >> + template<typename T> enum S<T>::E : int { a = X<T>() }; >> +} >> >> Modified: cfe/trunk/test/Modules/template-default-args.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/template-default-args.cpp?rev=300650&r1=300649&r2=300650&view=diff >> >> ============================================================================== >> --- cfe/trunk/test/Modules/template-default-args.cpp (original) >> +++ cfe/trunk/test/Modules/template-default-args.cpp Tue Apr 18 20:36:43 >> 2017 >> @@ -44,3 +44,18 @@ H<> h; // expected-error {{default argum >> I<> i; >> L<> *l; >> END >> + >> +namespace DeferredLookup { >> + template<typename T, typename U = T> using X = U; >> + template<typename T> void f() { (void) X<T>(); } >> + template<typename T> int n = X<T>(); // expected-warning {{extension}} >> + template<typename T> struct S { X<T> xt; enum E : int; }; >> + template<typename T> enum S<T>::E : int { a = X<T>() }; >> + >> + void test() { >> + f<int>(); >> + n<int> = 1; >> + S<int> s; >> + S<int>::E e = S<int>::E::a; >> + } >> +} >> >> >> _______________________________________________ >> cfe-commits mailing list >> cfe-commits@lists.llvm.org >> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >> >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits