
The relevant portion of C++ standard says [namespace.memdef]p3: If the name in a friend declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace. MSVC does not implement that rule for types. If there is a type in an enclosing namespace, they consider an unqualified tag declaration with the same name to be a redeclaration of the type from another namespace. Implementing compatibility is a simple matter of disabling our implementation of this rule for types, which was added in r177473. Reviewers: rsmith Differential Revision: http://reviews.llvm.org/D4443 llvm-svn: 212784
105 lines
2.1 KiB
C++
105 lines
2.1 KiB
C++
// RUN: %clang_cc1 %s -triple i686-pc-win32 -std=c++11 -Wmicrosoft -fms-compatibility -verify
|
|
// RUN: not %clang_cc1 %s -triple i686-pc-win32 -std=c++11 -Wmicrosoft -fms-compatibility -fdiagnostics-parseable-fixits 2>&1 | FileCheck %s
|
|
|
|
struct X;
|
|
namespace name_at_tu_scope {
|
|
struct Y {
|
|
friend struct X; // expected-warning-re {{unqualified friend declaration {{.*}} is a Microsoft extension}}
|
|
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:17-[[@LINE-1]]:17}:"::"
|
|
};
|
|
}
|
|
|
|
namespace enclosing_friend_decl {
|
|
struct B;
|
|
namespace ns {
|
|
struct A {
|
|
friend struct B; // expected-warning-re {{unqualified friend declaration {{.*}} is a Microsoft extension}}
|
|
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:17-[[@LINE-1]]:17}:"enclosing_friend_decl::"
|
|
protected:
|
|
A();
|
|
};
|
|
}
|
|
struct B {
|
|
static void f() { ns::A x; }
|
|
};
|
|
}
|
|
|
|
namespace enclosing_friend_qualified {
|
|
struct B;
|
|
namespace ns {
|
|
struct A {
|
|
friend struct enclosing_friend_qualified::B; // Adding name specifiers fixes it.
|
|
protected:
|
|
A();
|
|
};
|
|
}
|
|
struct B {
|
|
static void f() { ns::A x; }
|
|
};
|
|
}
|
|
|
|
namespace enclosing_friend_no_tag {
|
|
struct B;
|
|
namespace ns {
|
|
struct A {
|
|
friend B; // Removing the tag decl fixes it.
|
|
protected:
|
|
A();
|
|
};
|
|
}
|
|
struct B {
|
|
static void f() { ns::A x; }
|
|
};
|
|
}
|
|
|
|
namespace enclosing_friend_func {
|
|
void f();
|
|
namespace ns {
|
|
struct A {
|
|
// Amusingly, in MSVC, this declares ns::f(), and doesn't find the outer f().
|
|
friend void f();
|
|
protected:
|
|
A(); // expected-note {{declared protected here}}
|
|
};
|
|
}
|
|
void f() { ns::A x; } // expected-error {{calling a protected constructor of class 'enclosing_friend_func::ns::A'}}
|
|
}
|
|
|
|
namespace test_nns_fixit_hint {
|
|
namespace name1 {
|
|
namespace name2 {
|
|
struct X;
|
|
struct name2;
|
|
namespace name3 {
|
|
struct Y {
|
|
friend struct X; // expected-warning-re {{unqualified friend declaration {{.*}} is a Microsoft extension}}
|
|
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:17-[[@LINE-1]]:17}:"name1::name2::"
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// A friend declaration injects a forward declaration into the nearest enclosing
|
|
// non-member scope.
|
|
namespace friend_as_a_forward_decl {
|
|
|
|
class A {
|
|
class Nested {
|
|
friend class B;
|
|
B *b;
|
|
};
|
|
B *b;
|
|
};
|
|
B *global_b;
|
|
|
|
void f() {
|
|
class Local {
|
|
friend class Z;
|
|
Z *b;
|
|
};
|
|
Z *b;
|
|
}
|
|
|
|
}
|