Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

An extern declaration in block scope refers to an incorrect variable. #18551

Open Quuxplusone opened 10 years ago

Quuxplusone commented 10 years ago
Bugzilla Link PR18552
Status NEW
Importance P normal
Reported by Mitsuru Kariya (kariya_mitsuru@hotmail.com)
Reported on 2014-01-19 23:51:52 -0800
Last modified on 2015-12-04 08:47:27 -0800
Version unspecified
Hardware All All
CC dgregor@apple.com, llvm-bugs@lists.llvm.org, rafael@espindo.la, richard-llvm@metafoo.co.uk, stephan.bergmann.secondary@googlemail.com
Fixed by commit(s)
Attachments
Blocks
Blocked by
See also
I think that the following sample code should return 4, but clang returns 1.

// --- main.cc begin ---
static int i = 1;       // #1 i has internal linkage
int g() {
    int i = 2;          // #2 i has no linkage
    {
        extern int i;   // #3
        return i;
    }
}

int main()
{
    return g();
}
// --- main.cc end ---

// --- sub.cc begin ---
int i = 4;              // #4 i has external linkage
// --- sub.cc end ---

According to C++11 standard 3.5 p6, #3 should refer to #4 because #1 is not
visible from the point #3.
Quuxplusone commented 10 years ago

Per the current resolution of http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#426, we should reject this code. (Per the former resolution, the example has undefined behavior.)

Quuxplusone commented 10 years ago
Oh... I cannot understand why the issue #426 is disregarded.

In addition, I found 3.3.1 p4's note.
I think that it considers main.cc as ill-formed because #1 (has internal
linkage) and #3 (has external linkage) refer to the different entities (3.5 p9)
but has same name in a single declarative region (global namespace).
Quuxplusone commented 10 years ago
How about the sample code below?
ICBW, I think that the following sample code is compiled incorrectly with clang
3.4 or later.

#include <iostream>

namespace NS {
    int i = 1;                          // #1 has external linkage
}

static int i = 2;                       // #2 has internal linkage

int main()
{
    using NS::i;                        // It refers to #1, has external linkage.
    //extern int i;
    std::cout << i << std::endl;        // It refers to #1, of course.
    {
        extern int i;                   // I think it should refer to #1,
        std::cout << i << std::endl;    //  but it refers to #2.
    }
}

Acoording to 7.3.3 p1, a using-declaration introduces a name as a synomym.
And, according to 3.5 p6, if an declaration is visible and the declared entity
has a linkage, an "extern" declaration refers to the entity, and it only
ignores entities declared outside the innermost enclosing namespace scope.
NS::i has external linkage, So I think that the "extern int i;" should refer to
#1.

FYI, if a comment "//extern int i;" is uncommented, it refers to #1.

http://melpon.org/wandbox/permlink/vOM0nOdK36djcCHY
Quuxplusone commented 8 years ago
Some random related findings:

* For the related case of

  static int i;
  struct S {
      int i;
      static int f() {
          extern int i;
          return i;
      }
  };
  int main() { return S::f(); }

Clang does reference an external var.

* For the original example from comment 0, behaviour of at least Clang 3.2 and
3.3 was to reference an external var, only since 3.4 it references the static
var.  (But for the above struct-based example, behaviour has consistently been
the same ever since at least 3.2.)