r258524 - Merge templated static member variables, fixes http://llvm.org/pr26179.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 17 17:24:32 PST 2016


(And otherwise this LGTM.)

On Wed, Feb 17, 2016 at 5:24 PM, Richard Smith <richard at metafoo.co.uk> wrote:
> +      // TODO: Check visibility. New is hidden but has a complete type. If New
> +      // has no array bound, it should not inherit one from Old, if Old is not
> +      // visible.
>
> I think this is in the wrong place: it should be attached to the "old
> is complete and new is not" case. Also, our convention is to use
> FIXME, not TODO.
>
> Speaking of which, you can now delete the "FIXME: Even if this merging
> succeeds, [...]" comment now, and add its example as a testcase. With
> your change we should reliably diagnose it.
>
> On Wed, Feb 17, 2016 at 2:32 PM, Vassil Vassilev <v.g.vassilev at gmail.com> wrote:
>> On 16/02/16 22:20, Richard Smith wrote:
>>
>> --- a/lib/Sema/SemaLookup.cpp
>> +++ b/lib/Sema/SemaLookup.cpp
>> @@ -419,6 +419,25 @@ static bool isPreferredLookupResult(Sema &S,
>> Sema::LookupNameKind Kind,
>>      }
>>    }
>>
>> +  // VarDecl can have incomplete array types, prefer the one with more
>> complete
>> +  // array type.
>> +  if (VarDecl *DVD = dyn_cast<VarDecl>(DUnderlying)) {
>> +    VarDecl *EVD = cast<VarDecl>(EUnderlying);
>> +    // Skip local VarDecls with incomplete array type.
>> +    if ((!DVD->isLocalVarDecl() && DVD->hasExternalStorage()) ||
>> +        (!EVD->isLocalVarDecl() && EVD->hasExternalStorage())) {
>>
>> Why do you need this special case?
>>
>> No reason, I decided to be conservative. All comments should be addressed in
>> the new version of the patch.
>>
>> +
>> +      ASTContext &C = S.getASTContext();
>> +
>> +      if (const ArrayType *DVDTy = C.getAsArrayType(DVD->getType())) {
>> +        const ArrayType *EVDTy = C.getAsArrayType(EVD->getType());
>> +        // Prefer the decl with more complete type if visible.
>> +        return !DVDTy->isIncompleteArrayType() &&
>> EVDTy->isIncompleteArrayType()
>>
>> Checking for an array type here seems unnecessary -- it'd be simpler to
>> check EVD->getType()->isIncompleteType() &&
>> !DVD->getType()->isIncompleteType().
>>
>> +                 && S.isVisible(D);
>>
>> This seems like a very subtle case: we're performing redeclaration lookup
>> for a variable declaration X, and we find two results D and E. D is hidden
>> but has a complete type. E is visible but has an incomplete type. If X has
>> no array bound, it should not inherit one from D. But if it does have an
>> array bound, and that bound differs from E's bound, we should diagnose the
>> mismatch.
>>
>> Please add another test to the end of merge-incomplete-array-vars.cpp to
>> check this is working:
>> int c[2]; // expected-error {{different type: 'int [2]' vs 'int [1]'}}
>>
>> That said, I think this test will fail if you reorder c1 and c2 in the
>> module map, but that's a pre-existing bug (see the last FIXME in
>> Sema::MergeVarDeclTypes).
>>
>> +      }
>> +    }
>> +  }
>>
>>
>> On Tue, Feb 16, 2016 at 11:12 AM, Vassil Vassilev <v.g.vassilev at gmail.com>
>> wrote:
>>>
>>> ping...
>>>
>>> On 07/02/16 22:33, Vassil Vassilev wrote:
>>>
>>> Improve a comment.
>>> --Vassil
>>> On 07/02/16 20:48, Vassil Vassilev wrote:
>>>
>>> Would this patch be any better?
>>> --Vassil
>>> On 05/02/16 21:49, Richard Smith wrote:
>>>
>>> This belongs in ASTDeclReader::attachPreviousDecl[Impl]. That's where we
>>> propagate data that's supposed to be consistent across a redeclaration chain
>>> from earlier declarations to later ones.
>>>
>>> There's another wrinkle here: we should only be propagating the type from
>>> a previous declaration that's declared in the same scope (in particular, we
>>> should skip over declarations declared as local extern declarations within a
>>> function). This may in some cases require walking backwards along the
>>> redeclaration chain to find the previous declaration that was not a local
>>> extern declaration. That'd be observable in a case like this:
>>>
>>> modulemap:
>>> module A { module A1 { header "a1.h" } module A2 { header "a2.h" } }
>>> module B { header "b.h" }
>>>
>>> a1.h:
>>> int a[];
>>>
>>> b.h:
>>> void g(int(*)[], int);
>>> void g(int(*)[1], int) = delete;
>>> template<typename T> void f(T t) {
>>>   extern int a[];
>>>   g(&a, t);
>>> }
>>>
>>> a2.h:
>>> int a[1];
>>>
>>> x.cc:
>>> #include "a1.h"
>>> #include "b.h"
>>> void h() { f(0); } // should not produce an error; type of 'a' within 'f'
>>> should not have been updated
>>>
>>> That example actually reveals another problem: we really don't want the
>>> completed type to be visible unless there is a visible declaration with the
>>> completed type. That suggests that propagating the type across the
>>> redeclaration chain may be the wrong approach, and we should instead handle
>>> this by changing isPreferredLookupResult (in SemaLookup.cpp) to prefer a
>>> VarDecl with a complete type over one with an incomplete type.
>>>
>>> On Fri, Feb 5, 2016 at 12:27 PM, Vassil Vassilev <v.g.vassilev at gmail.com>
>>> wrote:
>>>>
>>>> I am not sure where else to put this logic if not in isSameEntity...
>>>> Could you point me to a better place?
>>>> --Vassil
>>>>
>>>> On 05/02/16 19:56, Richard Smith wrote:
>>>>
>>>> On Fri, Feb 5, 2016 at 7:04 AM, Vassil Vassilev <v.g.vassilev at gmail.com>
>>>> wrote:
>>>>>
>>>>> Good point. Do you have in mind calling 'clang::Sema::MergeVarDeclTypes'
>>>>> or we to just "duplicate" the logic in
>>>>> clang::ASTDeclReader::mergeRedeclarable?
>>>>
>>>>
>>>> It's not safe to call into Sema while we're in a partially-deserialized
>>>> state. We know the only interesting case here is complete versus incomplete
>>>> array types, so we don't need anything like the complexity of
>>>> MergeVarDeclTypes -- something as easy as "if (new type is incomplete and
>>>> old type is not) set new type to old type" should work.
>>>>
>>>>>
>>>>> On 05/02/16 02:50, Richard Smith via cfe-commits wrote:
>>>>>
>>>>> I suspect we'll need to do a little more than this: when we rebuild the
>>>>> redeclaration chain, we should probably propagate the complete type to later
>>>>> redeclarations in the same scope. Otherwise, if we import a module that has
>>>>> a complete type and one that has an incomplete type, the declaration found
>>>>> by name lookup might be the one with the incomplete type, possibly resulting
>>>>> in rejects-valid on code like this:
>>>>>
>>>>> a.h:
>>>>> extern int a[5];
>>>>>
>>>>> b.h:
>>>>> extern int a[];
>>>>>
>>>>> x.cc:
>>>>> #include "a.h"
>>>>> #include "b.h"
>>>>> int k = sizeof(a);
>>>>>
>>>>> On Fri, Jan 22, 2016 at 11:03 AM, Yaron Keren via cfe-commits
>>>>> <cfe-commits at lists.llvm.org> wrote:
>>>>>>
>>>>>> Author: yrnkrn
>>>>>> Date: Fri Jan 22 13:03:27 2016
>>>>>> New Revision: 258524
>>>>>>
>>>>>> URL: http://llvm.org/viewvc/llvm-project?rev=258524&view=rev
>>>>>> Log:
>>>>>> Merge templated static member variables, fixes http://llvm.org/pr26179.
>>>>>>
>>>>>> Patch by Vassil Vassilev!
>>>>>> Reviewed by Richard Smith.
>>>>>>
>>>>>>
>>>>>> Added:
>>>>>>     cfe/trunk/test/Modules/Inputs/PR26179/
>>>>>>     cfe/trunk/test/Modules/Inputs/PR26179/A.h
>>>>>>     cfe/trunk/test/Modules/Inputs/PR26179/B.h
>>>>>>     cfe/trunk/test/Modules/Inputs/PR26179/basic_string.h
>>>>>>     cfe/trunk/test/Modules/Inputs/PR26179/module.modulemap
>>>>>>     cfe/trunk/test/Modules/pr26179.cpp
>>>>>> Modified:
>>>>>>     cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
>>>>>>
>>>>>> Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
>>>>>> URL:
>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=258524&r1=258523&r2=258524&view=diff
>>>>>>
>>>>>> ==============================================================================
>>>>>> --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
>>>>>> +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Fri Jan 22 13:03:27
>>>>>> 2016
>>>>>> @@ -2595,8 +2595,24 @@ static bool isSameEntity(NamedDecl *X, N
>>>>>>    // Variables with the same type and linkage match.
>>>>>>    if (VarDecl *VarX = dyn_cast<VarDecl>(X)) {
>>>>>>      VarDecl *VarY = cast<VarDecl>(Y);
>>>>>> -    return (VarX->getLinkageInternal() == VarY->getLinkageInternal())
>>>>>> &&
>>>>>> -      VarX->getASTContext().hasSameType(VarX->getType(),
>>>>>> VarY->getType());
>>>>>> +    if (VarX->getLinkageInternal() == VarY->getLinkageInternal()) {
>>>>>> +      ASTContext &C = VarX->getASTContext();
>>>>>> +      if (C.hasSameType(VarX->getType(), VarY->getType()))
>>>>>> +        return true;
>>>>>> +
>>>>>> +      // We can get decls with different types on the redecl chain.
>>>>>> Eg.
>>>>>> +      // template <typename T> struct S { static T Var[]; }; // #1
>>>>>> +      // template <typename T> T S<T>::Var[sizeof(T)]; // #2
>>>>>> +      // Only? happens when completing an incomplete array type. In
>>>>>> this case
>>>>>> +      // when comparing #1 and #2 we should go through their elements
>>>>>> types.
>>>>>> +      const ArrayType *VarXTy = C.getAsArrayType(VarX->getType());
>>>>>> +      const ArrayType *VarYTy = C.getAsArrayType(VarY->getType());
>>>>>> +      if (!VarXTy || !VarYTy)
>>>>>> +        return false;
>>>>>> +      if (VarXTy->isIncompleteArrayType() ||
>>>>>> VarYTy->isIncompleteArrayType())
>>>>>> +        return C.hasSameType(VarXTy->getElementType(),
>>>>>> VarYTy->getElementType());
>>>>>> +    }
>>>>>> +    return false;
>>>>>>    }
>>>>>>
>>>>>>    // Namespaces with the same name and inlinedness match.
>>>>>>
>>>>>> Added: cfe/trunk/test/Modules/Inputs/PR26179/A.h
>>>>>> URL:
>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/PR26179/A.h?rev=258524&view=auto
>>>>>>
>>>>>> ==============================================================================
>>>>>> --- cfe/trunk/test/Modules/Inputs/PR26179/A.h (added)
>>>>>> +++ cfe/trunk/test/Modules/Inputs/PR26179/A.h Fri Jan 22 13:03:27 2016
>>>>>> @@ -0,0 +1,4 @@
>>>>>> +#include "basic_string.h"
>>>>>> +#include "B.h"
>>>>>> +
>>>>>> +int *p = a;
>>>>>>
>>>>>> Added: cfe/trunk/test/Modules/Inputs/PR26179/B.h
>>>>>> URL:
>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/PR26179/B.h?rev=258524&view=auto
>>>>>>
>>>>>> ==============================================================================
>>>>>> --- cfe/trunk/test/Modules/Inputs/PR26179/B.h (added)
>>>>>> +++ cfe/trunk/test/Modules/Inputs/PR26179/B.h Fri Jan 22 13:03:27 2016
>>>>>> @@ -0,0 +1,2 @@
>>>>>> +#include "basic_string.h"
>>>>>> +extern int a[5];
>>>>>>
>>>>>> Added: cfe/trunk/test/Modules/Inputs/PR26179/basic_string.h
>>>>>> URL:
>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/PR26179/basic_string.h?rev=258524&view=auto
>>>>>>
>>>>>> ==============================================================================
>>>>>> --- cfe/trunk/test/Modules/Inputs/PR26179/basic_string.h (added)
>>>>>> +++ cfe/trunk/test/Modules/Inputs/PR26179/basic_string.h Fri Jan 22
>>>>>> 13:03:27 2016
>>>>>> @@ -0,0 +1,14 @@
>>>>>> +#ifndef _GLIBCXX_STRING
>>>>>> +#define _GLIBCXX_STRING 1
>>>>>> +
>>>>>> +template<typename T>
>>>>>> +struct basic_string {
>>>>>> +  static T _S_empty_rep_storage[];
>>>>>> +};
>>>>>> +
>>>>>> +template<typename T>
>>>>>> +T basic_string<T>::_S_empty_rep_storage[sizeof(T)];
>>>>>> +
>>>>>> +extern int a[];
>>>>>> +
>>>>>> +#endif
>>>>>>
>>>>>> Added: cfe/trunk/test/Modules/Inputs/PR26179/module.modulemap
>>>>>> URL:
>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/PR26179/module.modulemap?rev=258524&view=auto
>>>>>>
>>>>>> ==============================================================================
>>>>>> --- cfe/trunk/test/Modules/Inputs/PR26179/module.modulemap (added)
>>>>>> +++ cfe/trunk/test/Modules/Inputs/PR26179/module.modulemap Fri Jan 22
>>>>>> 13:03:27 2016
>>>>>> @@ -0,0 +1,9 @@
>>>>>> +module A {
>>>>>> +  header "A.h"
>>>>>> +  export *
>>>>>> +}
>>>>>> +
>>>>>> +module B {
>>>>>> +  header "B.h"
>>>>>> +  export *
>>>>>> +}
>>>>>>
>>>>>> Added: cfe/trunk/test/Modules/pr26179.cpp
>>>>>> URL:
>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/pr26179.cpp?rev=258524&view=auto
>>>>>>
>>>>>> ==============================================================================
>>>>>> --- cfe/trunk/test/Modules/pr26179.cpp (added)
>>>>>> +++ cfe/trunk/test/Modules/pr26179.cpp Fri Jan 22 13:03:27 2016
>>>>>> @@ -0,0 +1,7 @@
>>>>>> +// RUN: rm -rf %t
>>>>>> +// RUN: %clang_cc1 -I%S/Inputs/PR26179 -verify %s
>>>>>> +// RUN: %clang_cc1 -fmodules
>>>>>> -fmodule-map-file=%S/Inputs/PR26179/module.modulemap -fmodules-cache-path=%t
>>>>>> -I%S/Inputs/PR26179 -verify %s
>>>>>> +
>>>>>> +#include "A.h"
>>>>>> +
>>>>>> +// expected-no-diagnostics
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> cfe-commits mailing list
>>>>>> cfe-commits at lists.llvm.org
>>>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> cfe-commits mailing list
>>>>> cfe-commits at lists.llvm.org
>>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>>>
>>>
>>
>>


More information about the cfe-commits mailing list