r300650 - [modules] Properly look up the owning module for an instantiation of a merged template.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 20 18:28:25 PDT 2017


Re-committed with fix in r300938.

On 20 April 2017 at 17:06, Richard Smith <richard at metafoo.co.uk> wrote:

> On 18 April 2017 at 22:41, Chandler Carruth <chandlerc at google.com> wrote:
>
>> Reverted in r300658.
>>
>
> For posterity, the above has an off-by-one error, the revert was r300659.
>
>
>> On Tue, Apr 18, 2017 at 8:30 PM Chandler Carruth <chandlerc at google.com>
>> wrote:
>>
>>> 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/libstd
>>>> c++-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(getPrimary
>>>>> Template()->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/DeclCX
>>>>> X.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/SemaL
>>>>> ookup.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->getTemplateInstantiationPa
>>>>> ttern())
>>>>>        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/20170420/bbe681c0/attachment-0001.html>


More information about the cfe-commits mailing list