<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Vassil and Richard,</div><div class=""><br class=""></div><div class="">After this commit, clang errors out when compiling the following code, which used to compile without any errors.</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">$ cat f2.cpp</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">extern int compile_time_assert_failed[1]; </span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">template <typename ></span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">class C {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">enum { D };</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">public:</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">template <typename A> void foo1() {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">  extern int compile_time_assert_failed[ ((int)C<A>::k > (int)D) ? 1 : -1];</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">};</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">template<></span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">class C<int> {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">public:</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">  const static int k = 2;</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">};</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">void foo2() {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">  C<char> c;</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">  c.foo1<int>();</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">$ cat f3.cpp </span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">void foo1() {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">  extern int foo0[1];</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">template<int n></span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">void foo2() {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">  extern int foo0[n ? 1 : -1];</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">void foo3() {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">  foo2<5>();</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div></span></div><div class="">The code looks legal, so I don’t think clang should complain?</div><div class=""><br class=""></div><div><blockquote type="cite" class=""><div class="">On Feb 28, 2016, at 11:08 AM, Vassil Vassilev via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org" class="">cfe-commits@lists.llvm.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="">Author: vvassilev<br class="">Date: Sun Feb 28 13:08:24 2016<br class="">New Revision: 262189<br class=""><br class="">URL: <a href="http://llvm.org/viewvc/llvm-project?rev=262189&view=rev" class="">http://llvm.org/viewvc/llvm-project?rev=262189&view=rev</a><br class="">Log:<br class="">[modules] Prefer more complete array types.<br class=""><br class="">If we import a module that has a complete array type and one that has an<br class="">incomplete array type, the declaration found by name lookup might be the one with<br class="">the incomplete type, possibly resulting in rejects-valid.<br class=""><br class="">Now, the name lookup prefers decls with a complete array types. Also,<br class="">diagnose cases when the redecl chain has array bound, different from the merge<br class="">candidate.<br class=""><br class="">Reviewed by Richard Smith.<br class=""><br class="">Modified:<br class="">    cfe/trunk/lib/Sema/SemaDecl.cpp<br class="">    cfe/trunk/lib/Sema/SemaLookup.cpp<br class="">    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp<br class="">    cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp<br class="">    cfe/trunk/test/Modules/Inputs/PR26179/A.h<br class="">    cfe/trunk/test/Modules/Inputs/PR26179/B.h<br class="">    cfe/trunk/test/Modules/Inputs/PR26179/basic_string.h<br class=""><br class="">Modified: cfe/trunk/lib/Sema/SemaDecl.cpp<br class="">URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=262189&r1=262188&r2=262189&view=diff" class="">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=262189&r1=262188&r2=262189&view=diff</a><br class="">==============================================================================<br class="">--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)<br class="">+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun Feb 28 13:08:24 2016<br class="">@@ -3245,6 +3245,22 @@ void Sema::mergeObjCMethodDecls(ObjCMeth<br class="">   CheckObjCMethodOverride(newMethod, oldMethod);<br class=""> }<br class=""><br class="">+static void diagnoseVarDeclTypeMismatch(Sema &S, VarDecl *New, VarDecl* Old) {<br class="">+  assert(!S.Context.hasSameType(New->getType(), Old->getType()));<br class="">+<br class="">+  S.Diag(New->getLocation(), New->isThisDeclarationADefinition()<br class="">+         ? diag::err_redefinition_different_type<br class="">+         : diag::err_redeclaration_different_type)<br class="">+    << New->getDeclName() << New->getType() << Old->getType();<br class="">+<br class="">+  diag::kind PrevDiag;<br class="">+  SourceLocation OldLocation;<br class="">+  std::tie(PrevDiag, OldLocation)<br class="">+    = getNoteDiagForInvalidRedeclaration(Old, New);<br class="">+  S.Diag(OldLocation, PrevDiag);<br class="">+  New->setInvalidDecl();<br class="">+}<br class="">+<br class=""> /// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and<br class=""> /// scope as a previous declaration 'Old'.  Figure out how to merge their types,<br class=""> /// emitting diagnostics as appropriate.<br class="">@@ -3271,21 +3287,40 @@ void Sema::MergeVarDeclTypes(VarDecl *Ne<br class="">     //   object or function shall be identical, except that declarations for an<br class="">     //   array object can specify array types that differ by the presence or<br class="">     //   absence of a major array bound (8.3.4).<br class="">-    else if (Old->getType()->isIncompleteArrayType() &&<br class="">-             New->getType()->isArrayType()) {<br class="">-      const ArrayType *OldArray = Context.getAsArrayType(Old->getType());<br class="">-      const ArrayType *NewArray = Context.getAsArrayType(New->getType());<br class="">-      if (Context.hasSameType(OldArray->getElementType(),<br class="">-                              NewArray->getElementType()))<br class="">-        MergedT = New->getType();<br class="">-    } else if (Old->getType()->isArrayType() &&<br class="">-               New->getType()->isIncompleteArrayType()) {<br class="">+    else if (Old->getType()->isArrayType() && New->getType()->isArrayType()) {<br class="">       const ArrayType *OldArray = Context.getAsArrayType(Old->getType());<br class="">       const ArrayType *NewArray = Context.getAsArrayType(New->getType());<br class="">-      if (Context.hasSameType(OldArray->getElementType(),<br class="">-                              NewArray->getElementType()))<br class="">-        MergedT = Old->getType();<br class="">-    } else if (New->getType()->isObjCObjectPointerType() &&<br class="">+<br class="">+      // We are merging a variable declaration New into Old. If it has an array<br class="">+      // bound, and that bound differs from Old's bound, we should diagnose the<br class="">+      // mismatch.<br class="">+      if (!NewArray->isIncompleteArrayType()) {<br class="">+        for (VarDecl *PrevVD = Old->getMostRecentDecl(); PrevVD;<br class="">+             PrevVD = PrevVD->getPreviousDecl()) {<br class="">+          const ArrayType *PrevVDTy = Context.getAsArrayType(PrevVD->getType());<br class="">+          if (PrevVDTy->isIncompleteArrayType())<br class="">+            continue;<br class="">+<br class="">+          if (!Context.hasSameType(NewArray, PrevVDTy))<br class="">+            return diagnoseVarDeclTypeMismatch(*this, New, PrevVD);<br class="">+        }<br class="">+      }<br class="">+<br class="">+      if (OldArray->isIncompleteArrayType() && NewArray->isArrayType()) {<br class="">+        if (Context.hasSameType(OldArray->getElementType(),<br class="">+                                NewArray->getElementType()))<br class="">+          MergedT = New->getType();<br class="">+      }<br class="">+      // FIXME: Check visibility. New is hidden but has a complete type. If New<br class="">+      // has no array bound, it should not inherit one from Old, if Old is not<br class="">+      // visible.<br class="">+      else if (OldArray->isArrayType() && NewArray->isIncompleteArrayType()) {<br class="">+        if (Context.hasSameType(OldArray->getElementType(),<br class="">+                                NewArray->getElementType()))<br class="">+          MergedT = Old->getType();<br class="">+      }<br class="">+    }<br class="">+    else if (New->getType()->isObjCObjectPointerType() &&<br class="">                Old->getType()->isObjCObjectPointerType()) {<br class="">       MergedT = Context.mergeObjCGCQualifiers(New->getType(),<br class="">                                               Old->getType());<br class="">@@ -3311,27 +3346,7 @@ void Sema::MergeVarDeclTypes(VarDecl *Ne<br class="">         New->setType(Context.DependentTy);<br class="">       return;<br class="">     }<br class="">-<br class="">-    // FIXME: Even if this merging succeeds, some other non-visible declaration<br class="">-    // of this variable might have an incompatible type. For instance:<br class="">-    //<br class="">-    //   extern int arr[];<br class="">-    //   void f() { extern int arr[2]; }<br class="">-    //   void g() { extern int arr[3]; }<br class="">-    //<br class="">-    // Neither C nor C++ requires a diagnostic for this, but we should still try<br class="">-    // to diagnose it.<br class="">-    Diag(New->getLocation(), New->isThisDeclarationADefinition()<br class="">-                                 ? diag::err_redefinition_different_type<br class="">-                                 : diag::err_redeclaration_different_type)<br class="">-        << New->getDeclName() << New->getType() << Old->getType();<br class="">-<br class="">-    diag::kind PrevDiag;<br class="">-    SourceLocation OldLocation;<br class="">-    std::tie(PrevDiag, OldLocation) =<br class="">-        getNoteDiagForInvalidRedeclaration(Old, New);<br class="">-    Diag(OldLocation, PrevDiag);<br class="">-    return New->setInvalidDecl();<br class="">+    return diagnoseVarDeclTypeMismatch(*this, New, Old);<br class="">   }<br class=""><br class="">   // Don't actually update the type on the new declaration if the old<br class=""><br class="">Modified: cfe/trunk/lib/Sema/SemaLookup.cpp<br class="">URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=262189&r1=262188&r2=262189&view=diff" class="">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=262189&r1=262188&r2=262189&view=diff</a><br class="">==============================================================================<br class="">--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)<br class="">+++ cfe/trunk/lib/Sema/SemaLookup.cpp Sun Feb 28 13:08:24 2016<br class="">@@ -419,6 +419,18 @@ static bool isPreferredLookupResult(Sema<br class="">     }<br class="">   }<br class=""><br class="">+  // VarDecl can have incomplete array types, prefer the one with more complete<br class="">+  // array type.<br class="">+  if (VarDecl *DVD = dyn_cast<VarDecl>(DUnderlying)) {<br class="">+    VarDecl *EVD = cast<VarDecl>(EUnderlying);<br class="">+    if (EVD->getType()->isIncompleteType() &&<br class="">+        !DVD->getType()->isIncompleteType()) {<br class="">+      // Prefer the decl with a more complete type if visible.<br class="">+      return S.isVisible(DVD);<br class="">+    }<br class="">+    return false; // Avoid picking up a newer decl, just because it was newer.<br class="">+  }<br class="">+<br class="">   // For most kinds of declaration, it doesn't really matter which one we pick.<br class="">   if (!isa<FunctionDecl>(DUnderlying) && !isa<VarDecl>(DUnderlying)) {<br class="">     // If the existing declaration is hidden, prefer the new one. Otherwise,<br class=""><br class="">Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp<br class="">URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=262189&r1=262188&r2=262189&view=diff" class="">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=262189&r1=262188&r2=262189&view=diff</a><br class="">==============================================================================<br class="">--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)<br class="">+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Sun Feb 28 13:08:24 2016<br class="">@@ -2613,7 +2613,7 @@ static bool isSameEntity(NamedDecl *X, N<br class="">       // template <typename T> struct S { static T Var[]; }; // #1<br class="">       // template <typename T> T S<T>::Var[sizeof(T)]; // #2<br class="">       // Only? happens when completing an incomplete array type. In this case<br class="">-      // when comparing #1 and #2 we should go through their elements types.<br class="">+      // when comparing #1 and #2 we should go through their element type.<br class="">       const ArrayType *VarXTy = C.getAsArrayType(VarX->getType());<br class="">       const ArrayType *VarYTy = C.getAsArrayType(VarY->getType());<br class="">       if (!VarXTy || !VarYTy)<br class=""><br class="">Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp<br class="">URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp?rev=262189&r1=262188&r2=262189&view=diff" class="">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp?rev=262189&r1=262188&r2=262189&view=diff</a><br class="">==============================================================================<br class="">--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp (original)<br class="">+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp Sun Feb 28 13:08:24 2016<br class="">@@ -207,3 +207,7 @@ namespace use_outside_ns {<br class="">     int j() { return sizeof(d); }<br class="">   }<br class=""> }<br class="">+<br class="">+extern int arr[];<br class="">+void f1() { extern int arr[2]; } // expected-note {{previous}}<br class="">+void f2() { extern int arr[3]; } // expected-error {{different type: 'int [3]' vs 'int [2]'}}<br class=""><br class="">Modified: cfe/trunk/test/Modules/Inputs/PR26179/A.h<br class="">URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/PR26179/A.h?rev=262189&r1=262188&r2=262189&view=diff" class="">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/PR26179/A.h?rev=262189&r1=262188&r2=262189&view=diff</a><br class="">==============================================================================<br class="">--- cfe/trunk/test/Modules/Inputs/PR26179/A.h (original)<br class="">+++ cfe/trunk/test/Modules/Inputs/PR26179/A.h Sun Feb 28 13:08:24 2016<br class="">@@ -1,4 +1,2 @@<br class=""> #include "basic_string.h"<br class=""> #include "B.h"<br class="">-<br class="">-int *p = a;<br class=""><br class="">Modified: cfe/trunk/test/Modules/Inputs/PR26179/B.h<br class="">URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/PR26179/B.h?rev=262189&r1=262188&r2=262189&view=diff" class="">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/PR26179/B.h?rev=262189&r1=262188&r2=262189&view=diff</a><br class="">==============================================================================<br class="">--- cfe/trunk/test/Modules/Inputs/PR26179/B.h (original)<br class="">+++ cfe/trunk/test/Modules/Inputs/PR26179/B.h Sun Feb 28 13:08:24 2016<br class="">@@ -1,2 +1 @@<br class=""> #include "basic_string.h"<br class="">-extern int a[5];<br class=""><br class="">Modified: cfe/trunk/test/Modules/Inputs/PR26179/basic_string.h<br class="">URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/PR26179/basic_string.h?rev=262189&r1=262188&r2=262189&view=diff" class="">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/PR26179/basic_string.h?rev=262189&r1=262188&r2=262189&view=diff</a><br class="">==============================================================================<br class="">--- cfe/trunk/test/Modules/Inputs/PR26179/basic_string.h (original)<br class="">+++ cfe/trunk/test/Modules/Inputs/PR26179/basic_string.h Sun Feb 28 13:08:24 2016<br class="">@@ -9,6 +9,4 @@ struct basic_string {<br class=""> template<typename T><br class=""> T basic_string<T>::_S_empty_rep_storage[sizeof(T)];<br class=""><br class="">-extern int a[];<br class="">-<br class=""> #endif<br class=""><br class=""><br class="">_______________________________________________<br class="">cfe-commits mailing list<br class=""><a href="mailto:cfe-commits@lists.llvm.org" class="">cfe-commits@lists.llvm.org</a><br class="">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits<br class=""></div></div></blockquote></div><br class=""></body></html>