Switch the semantic DeclContext for a block-scope declaration of a function or
variable from being the function to being the enclosing namespace scope (in
C++) or the TU (in C). This allows us to fix a selection of related issues
where we would build incorrect redeclaration chains for such declarations, and
fail to notice type mismatches.
Such declarations are put into a new IdentifierNamespace, IDNS_LocalExtern,
which is only found when searching scopes, and not found when searching
DeclContexts. Such a declaration is only made visible in its DeclContext if
there are no non-LocalExtern declarations.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191064 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/CXX/basic/basic.link/p7.cpp b/test/CXX/basic/basic.link/p7.cpp
new file mode 100644
index 0000000..9a85eac
--- /dev/null
+++ b/test/CXX/basic/basic.link/p7.cpp
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -verify -std=c++1y %s
+
+// Example from the standard.
+namespace X {
+ void p() {
+ q(); // expected-error {{undeclared}}
+ extern void q();
+ }
+ void middle() {
+ q(); // expected-error {{undeclared}}
+ }
+ void q() { /*...*/ }
+ void bottom() {
+ q();
+ }
+}
+int q();
+
+namespace Test1 {
+ void f() {
+ extern int a; // expected-note {{previous}}
+ int g(void); // expected-note {{previous}}
+ }
+ double a; // expected-error {{different type: 'double' vs 'int'}}
+ double g(); // expected-error {{differ only in their return type}}
+}
+
+namespace Test2 {
+ void f() {
+ extern int a; // expected-note {{previous}}
+ int g(void); // expected-note {{previous}}
+ }
+ void h() {
+ extern double a; // expected-error {{different type: 'double' vs 'int'}}
+ double g(void); // expected-error {{differ only in their return type}}
+ }
+}
+
+namespace Test3 {
+ constexpr void (*f())() {
+ void h();
+ return &h;
+ }
+ constexpr void (*g())() {
+ void h();
+ return &h;
+ }
+ static_assert(f() == g(), "");
+}
+
+namespace Test4 {
+ template<typename T>
+ constexpr void (*f())() {
+ void h();
+ return &h;
+ }
+ static_assert(f<int>() == f<char>(), "");
+ void h();
+ static_assert(f<int>() == &h, "");
+}
+
+namespace Test5 {
+ constexpr auto f() -> void (*)() {
+ void g();
+ struct X {
+ friend void g();
+ static constexpr auto h() -> void (*)() { return g; }
+ };
+ return X::h();
+ }
+ void g();
+ static_assert(f() == g, "");
+}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
index 2dbc143..e040d5b 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
@@ -61,6 +61,8 @@
int x = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
}
int y = sizeof(array);
+ extern int array[];
+ int z = sizeof(array);
}
}
@@ -71,6 +73,19 @@
int x = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
}
int y = sizeof(array);
+ extern int array[];
+ int z = sizeof(array);
+}
+
+namespace test8 {
+ extern int array[];
+ void test() {
+ extern int array[100];
+ int x = sizeof(array);
+ }
+ int y = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+ extern int array[];
+ int z = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
}
namespace dependent {
@@ -143,10 +158,52 @@
}
template<typename T> void n() {
- extern T n_var;
+ extern T n_var; // expected-error {{redefinition of 'n_var' with a different type: 'double' vs 'int'}} expected-note {{previous}}
+ extern T n_fn(); // expected-error {{functions that differ only in their return type cannot be overloaded}} expected-note {{previous}}
}
template void n<int>();
- // FIXME: Diagnose this!
- float n_var;
- template void n<double>();
+ template void n<double>(); // expected-note {{in instantiation of}}
+
+ template<typename T> void o() {
+ extern T o_var; // expected-note {{previous}}
+ extern T o_fn(); // expected-note {{previous}}
+ }
+ template void o<int>();
+ float o_var; // expected-error {{redefinition of 'o_var' with a different type: 'float' vs 'int'}}
+ float o_fn(); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+
+ int p_var;
+ int p_fn();
+ template<typename T> void p() {
+ extern T p_var;
+ extern T p_fn();
+ }
+}
+
+namespace use_outside_ns {
+ namespace A {
+ extern int a[3];
+ extern int b[];
+ extern int c[3];
+ void f() {
+ extern int a[];
+ extern int b[3];
+ }
+ template<typename T> void x() {
+ extern T c;
+ extern T d;
+ }
+ extern int d[3];
+ template void x<int[]>();
+ }
+ int w = sizeof(A::a);
+ int x = sizeof(A::b); // expected-error {{incomplete}}
+ int y = sizeof(A::c);
+ int z = sizeof(A::d);
+ namespace A {
+ int g() { return sizeof(a); }
+ int h() { return sizeof(b); } // expected-error {{incomplete}}
+ int i() { return sizeof(c); }
+ int j() { return sizeof(d); }
+ }
}
diff --git a/test/CXX/drs/dr0xx.cpp b/test/CXX/drs/dr0xx.cpp
index f8ac57f..70a9e49 100644
--- a/test/CXX/drs/dr0xx.cpp
+++ b/test/CXX/drs/dr0xx.cpp
@@ -280,7 +280,7 @@
// dr28: na
-namespace dr29 { // dr29: no
+namespace dr29 { // dr29: 3.4
void dr29_f0(); // expected-note {{here}}
void g0() { void dr29_f0(); }
extern "C++" void g0_cxx() { void dr29_f0(); }
@@ -291,17 +291,14 @@
extern "C" void g1_c() { void dr29_f1(); }
extern "C++" void g1_cxx() { void dr29_f1(); } // expected-error {{different language linkage}}
- // FIXME: We should reject this.
- void g2() { void dr29_f2(); }
- extern "C" void dr29_f2();
+ void g2() { void dr29_f2(); } // expected-note {{here}}
+ extern "C" void dr29_f2(); // expected-error {{different language linkage}}
- // FIXME: We should reject this.
- extern "C" void g3() { void dr29_f3(); }
- extern "C++" void dr29_f3();
+ extern "C" void g3() { void dr29_f3(); } // expected-note {{here}}
+ extern "C++" void dr29_f3(); // expected-error {{different language linkage}}
- // FIXME: We should reject this.
- extern "C++" void g4() { void dr29_f4(); }
- extern "C" void dr29_f4();
+ extern "C++" void g4() { void dr29_f4(); } // expected-note {{here}}
+ extern "C" void dr29_f4(); // expected-error {{different language linkage}}
extern "C" void g5();
extern "C++" void dr29_f5();
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index f03f499..775cf00 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -9,7 +9,7 @@
// CHECK: @_ZGVZN1N1gEvE1a = internal global
//CHECK: @pr5966_i = external global
-//CHECK: @_ZL8pr5966_i = internal global
+//CHECK: @_ZL8pr5966_j = internal global
// CHECK-LABEL: define zeroext i1 @_ZplRK1YRA100_P1X
bool operator+(const Y&, X* (&xs)[100]) { return false; }
@@ -314,10 +314,10 @@
pr5966_i = 0;
}
-static int pr5966_i;
+static int pr5966_j;
void pr5966_bar() {
- pr5966_i = 0;
+ pr5966_j = 0;
}
namespace test0 {
@@ -652,10 +652,10 @@
foo();
}
- static char foo() {}
+ static char bar() {}
void test1() {
- // CHECK: call signext i8 @_ZN6test24L3fooEv()
- foo();
+ // CHECK: call signext i8 @_ZN6test24L3barEv()
+ bar();
}
}
diff --git a/test/Index/usrs.m b/test/Index/usrs.m
index dccfb75..cc2e0fd 100644
--- a/test/Index/usrs.m
+++ b/test/Index/usrs.m
@@ -118,7 +118,7 @@
// CHECK: usrs.m c:objc(cs)Foo Extent=[34:1 - 45:2]
// CHECK: usrs.m c:objc(cs)Foo(im)godzilla Extent=[35:1 - 39:2]
// CHECK: usrs.m c:usrs.m@402objc(cs)Foo(im)godzilla@a Extent=[36:3 - 36:19]
-// CHECK: usrs.m c:objc(cs)Foo(im)godzilla@z Extent=[37:3 - 37:15]
+// CHECK: usrs.m c:@z Extent=[37:3 - 37:15]
// CHECK: usrs.m c:objc(cs)Foo(cm)kingkong Extent=[40:1 - 43:2]
// CHECK: usrs.m c:usrs.m@470objc(cs)Foo(cm)kingkong@local_var Extent=[41:3 - 41:16]
// CHECK: usrs.m c:objc(cs)Foo(py)d1 Extent=[44:1 - 44:15]
diff --git a/test/Sema/struct-decl.c b/test/Sema/struct-decl.c
index 819e856..8d3d74d 100644
--- a/test/Sema/struct-decl.c
+++ b/test/Sema/struct-decl.c
@@ -57,3 +57,12 @@
inline struct test3 { // expected-error {{'inline' can only appear on functions}}
int x;
};
+
+struct hiding_1 {};
+struct hiding_2 {};
+void test_hiding() {
+ struct hiding_1 *hiding_1();
+ extern struct hiding_2 *hiding_2;
+ struct hiding_1 *p = hiding_1();
+ struct hiding_2 *q = hiding_2;
+}
diff --git a/test/SemaCXX/blocks-1.cpp b/test/SemaCXX/blocks-1.cpp
index 02e9cac..e11fd92 100644
--- a/test/SemaCXX/blocks-1.cpp
+++ b/test/SemaCXX/blocks-1.cpp
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks -std=c++11
-// expected-no-diagnostics
+// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks -std=c++1y
extern "C" int exit(int);
@@ -57,3 +56,18 @@
foo(a);
};
}
+
+namespace LocalDecls {
+ void f() {
+ (void) ^{
+ extern int a; // expected-note {{previous}}
+ extern int b(); // expected-note {{previous}}
+ };
+ }
+ void g() {
+ (void) ^{
+ extern float a; // expected-error {{different type}}
+ extern float b(); // expected-error {{cannot be overloaded}}
+ };
+ }
+}
diff --git a/test/SemaCXX/cxx0x-initializer-references.cpp b/test/SemaCXX/cxx0x-initializer-references.cpp
index 48236fd..9096c8a 100644
--- a/test/SemaCXX/cxx0x-initializer-references.cpp
+++ b/test/SemaCXX/cxx0x-initializer-references.cpp
@@ -36,10 +36,10 @@
};
void call() {
- void f(const int&);
+ one f(const int&);
f({1});
- void g(int&); // expected-note {{passing argument}}
+ one g(int&); // expected-note {{passing argument}}
g({1}); // expected-error {{cannot bind to an initializer list temporary}}
int i = 0;
g({i});
diff --git a/test/SemaCXX/extern-c.cpp b/test/SemaCXX/extern-c.cpp
index 30b8fe69..2bf9535 100644
--- a/test/SemaCXX/extern-c.cpp
+++ b/test/SemaCXX/extern-c.cpp
@@ -29,16 +29,27 @@
}
}
-extern "C" {
- void test4_f() {
- extern int test4_b; // expected-note {{declared with C language linkage here}}
+namespace N {
+ extern "C" {
+ void test4_f() {
+ extern int test4_b; // expected-note {{declared with C language linkage here}}
+ }
}
}
static float test4_b; // expected-error {{declaration of 'test4_b' in global scope conflicts with declaration with C language linkage}}
extern "C" {
- void test5_f() {
- extern int test5_b; // expected-note {{declared with C language linkage here}}
+ void test4c_f() {
+ extern int test4_c; // expected-note {{previous}}
+ }
+}
+static float test4_c; // expected-error {{redefinition of 'test4_c' with a different type: 'float' vs 'int'}}
+
+namespace N {
+ extern "C" {
+ void test5_f() {
+ extern int test5_b; // expected-note {{declared with C language linkage here}}
+ }
}
}
extern "C" {
@@ -46,6 +57,15 @@
}
extern "C" {
+ void test5c_f() {
+ extern int test5_c; // expected-note {{previous}}
+ }
+}
+extern "C" {
+ static float test5_c; // expected-error {{redefinition of 'test5_c' with a different type: 'float' vs 'int'}}
+}
+
+extern "C" {
void f() {
extern int test6_b;
}
diff --git a/test/SemaCXX/function-redecl.cpp b/test/SemaCXX/function-redecl.cpp
index deb8e9d..2bc0d90 100644
--- a/test/SemaCXX/function-redecl.cpp
+++ b/test/SemaCXX/function-redecl.cpp
@@ -4,17 +4,14 @@
namespace N {
void f1() {
void foo(int); // okay
- void bar(int);
+ void bar(int); // expected-note 2{{previous declaration is here}}
}
void foo(int); // expected-note 2{{previous declaration is here}}
void f2() {
int foo(int); // expected-error {{functions that differ only in their return type cannot be overloaded}}
- // FIXME: We should be able to diagnose the conflict between this
- // declaration of 'bar' and the previous one, even though they come
- // from different lexical scopes.
- int bar(int); // expected-note {{previous declaration is here}}
+ int bar(int); // expected-error {{functions that differ only in their return type cannot be overloaded}}
int baz(int); // expected-note {{previous declaration is here}}
{
diff --git a/test/SemaCXX/warn-unreachable.cpp b/test/SemaCXX/warn-unreachable.cpp
index f36300a..dd07125 100644
--- a/test/SemaCXX/warn-unreachable.cpp
+++ b/test/SemaCXX/warn-unreachable.cpp
@@ -62,8 +62,8 @@
struct S {
int mem;
} s;
- S &foor() __attribute__((noreturn));
- foor()
+ S &foonr() __attribute__((noreturn));
+ foonr()
.mem; // expected-warning {{will never be executed}}
}