r300650 - [modules] Properly look up the owning module for an instantiation of a merged template.
Chandler Carruth via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 18 20:30:16 PDT 2017
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 <chandlerc at 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 at 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 at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20170419/6d102beb/attachment-0001.html>
More information about the cfe-commits
mailing list