From b306bcc266a7ee2313b12f8d78af7c03b76dba7a Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Thu, 25 Feb 2010 09:32:59 +0000 Subject: [PATCH] Fix a really trivial crasher and begin fleshing out one of the namespace test cases. llvm-svn: 97134 --- clang/lib/Sema/SemaDecl.cpp | 11 +++-- .../namespace.def/namespace.memdef/p3.cpp | 43 ++++++++++++++++++- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 27eb2510ec55..47c787b0c42e 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4778,12 +4778,15 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // If a friend declaration in a non-local class first declares a // class or function, the friend class or function is a member of // the innermost enclosing namespace. - while (!SearchDC->isFileContext()) - SearchDC = SearchDC->getParent(); + SearchDC = SearchDC->getEnclosingNamespaceContext(); - // The entity of a decl scope is a DeclContext; see PushDeclContext. - while (S->getEntity() != SearchDC) + // Look up through our scopes until we find one with an entity which + // matches our declaration context. + while (S->getEntity() && + ((DeclContext *)S->getEntity())->getPrimaryContext() != SearchDC) { S = S->getParent(); + assert(S && "No enclosing scope matching the enclosing namespace."); + } } CreateNewDecl: diff --git a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp index 1f962a98db6e..a5f314dac239 100644 --- a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp +++ b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp @@ -1,5 +1,47 @@ // RUN: %clang_cc1 -fsyntax-only %s +// C++'0x [namespace.memdef] p3: +// Every name first declared in a namespace is a member of that namespace. If +// a friend declaration in a non-local class first declares a class or +// function the friend class or function is a member of the innermost +// enclosing namespace. + +namespace N { + struct S0 { + friend struct F0; + friend void f0(int); + struct F0 member_func(); + }; + struct F0 { }; + F0 f0() { return S0().member_func(); } +} +N::F0 f0_var = N::f0(); + +// Ensure we can handle attaching friend declarations to an enclosing namespace +// with multiple contexts. +namespace N { struct S1 { struct IS1; }; } +namespace N { + struct S1::IS1 { + friend struct F1; + friend void f1(int); + struct F1 member_func(); + }; + struct F1 { }; + F1 f1() { return S1::IS1().member_func(); } +} +N::F1 f1_var = N::f1(); + +// The name of the friend is not found by unqualified lookup (3.4.1) or by +// qualified lookup (3.4.3) until a matching declaration is provided in that +// namespace scope (either before or after the class definition granting +// friendship). If a friend function is called, its name may be found by the +// name lookup that considers functions from namespaces and classes +// associated with the types of the function arguments (3.4.2). 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. + template struct X0 { }; struct X1 { }; @@ -11,5 +53,4 @@ struct Y { friend union X1; }; - // FIXME: Woefully inadequate for testing -- GitLab