From 7bf3600f56342dc434dad994d0c71068e5d3b5c7 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Mon, 1 Mar 2010 21:17:36 +0000 Subject: [PATCH] Fix the lookup of names used in a friend declaration to not attempt to re-declare them. This fixes PR6317. Also add the beginnings of an interesting test case for p1 of [class.friend] which also covers PR6317. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97499 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaDecl.cpp | 5 +- test/CXX/class.access/class.friend/p1.cpp | 62 +++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 test/CXX/class.access/class.friend/p1.cpp diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 4842da2a7b..1d448d0de8 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4535,8 +4535,9 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, bool isStdBadAlloc = false; bool Invalid = false; - RedeclarationKind Redecl = (TUK != TUK_Reference ? ForRedeclaration - : NotForRedeclaration); + RedeclarationKind Redecl = ForRedeclaration; + if (TUK == TUK_Friend || TUK == TUK_Reference) + Redecl = NotForRedeclaration; LookupResult Previous(*this, Name, NameLoc, LookupTagName, Redecl); diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp new file mode 100644 index 0000000000..22f77b0955 --- /dev/null +++ b/test/CXX/class.access/class.friend/p1.cpp @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// C++'0x [class.friend] p1: +// A friend of a class is a function or class that is given permission to use +// the private and protected member names from the class. A class specifies +// its friends, if any, by way of friend declarations. Such declarations give +// special access rights to the friends, but they do not make the nominated +// friends members of the befriending class. +// +// FIXME: Add tests for access control when implemented. Currently we only test +// for parsing. + +struct S { static void f(); }; +S* g() { return 0; } + +struct X { + friend struct S; + friend S* g(); +}; + +void test1() { + S s; + g()->f(); + S::f(); + X::g(); // expected-error{{no member named 'g' in 'struct X'}} + X::S x_s; // expected-error{{no member named 'S' in 'struct X'}} + X x; + x.g(); // expected-error{{no member named 'g' in 'struct X'}} +} + +// Test that we recurse through namespaces to find already declared names, but +// new names are declared within the enclosing namespace. +namespace N { + struct X { + friend struct S; + friend S* g(); + + friend struct S2; + friend struct S2* g2(); + }; + + struct S2 { static void f2(); }; + S2* g2() { return 0; } + + void test() { + g()->f(); + S s; + S::f(); + X::g(); // expected-error{{no member named 'g' in 'struct N::X'}} + X::S x_s; // expected-error{{no member named 'S' in 'struct N::X'}} + X x; + x.g(); // expected-error{{no member named 'g' in 'struct N::X'}} + + g2(); + S2 s2; + ::g2(); // expected-error{{no member named 'g2' in the global namespace}} + ::S2 g_s2; // expected-error{{no member named 'S2' in the global namespace}} + X::g2(); // expected-error{{no member named 'g2' in 'struct N::X'}} + X::S2 x_s2; // expected-error{{no member named 'S2' in 'struct N::X'}} + x.g2(); // expected-error{{no member named 'g2' in 'struct N::X'}} + } +}