From: Yaron Keren Date: Mon, 17 Apr 2017 08:51:20 +0000 (+0000) Subject: Address http://bugs.llvm.org/pr30994 so that a non-friend can properly replace a... X-Git-Tag: llvmorg-5.0.0-rc1~7566 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=27e2ff964fc3e18c27488e15dc74b44ef32d2fe0;p=platform%2Fupstream%2Fllvm.git Address bugs.llvm.org/pr30994 so that a non-friend can properly replace a friend, and a visible friend can properly replace an invisible friend but not vice verse, and definitions are not replaced. This fixes the two FIXME in SemaTemplate/friend-template.cpp. The code implements Richard Smith suggestion in comment 3 of the PR. reviewer: Vassil Vassilev Differential Revision: https://reviews.llvm.org/D31540 llvm-svn: 300443 --- diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index c88cb6a..5ca1f1e 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -417,6 +417,8 @@ public: return const_cast(this)->getTranslationUnitDecl(); } + bool isThisDeclarationADefinition() const; + bool isInAnonymousNamespace() const; bool isInStdNamespace() const; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 2b22e5b..6a288cd 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1536,6 +1536,10 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD, bool IsKnownNewer) const { if (isa(this)) return false; + if (getFriendObjectKind() > OldD->getFriendObjectKind() && + !isThisDeclarationADefinition()) + return false; + // For parameters, pick the newer one. This is either an error or (in // Objective-C) permitted as an extension. if (isa(this)) diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index cda70c5..ae74445 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -861,6 +861,21 @@ const FunctionType *Decl::getFunctionType(bool BlocksToo) const { return Ty->getAs(); } +bool Decl::isThisDeclarationADefinition() const { + if (auto *TD = dyn_cast(this)) + return TD->isThisDeclarationADefinition(); + if (auto *FD = dyn_cast(this)) + return FD->isThisDeclarationADefinition(); + if (auto *VD = dyn_cast(this)) + return VD->isThisDeclarationADefinition(); + if (auto *CTD = dyn_cast(this)) + return CTD->isThisDeclarationADefinition(); + if (auto *FTD = dyn_cast(this)) + return FTD->isThisDeclarationADefinition(); + if (auto *VTD = dyn_cast(this)) + return VTD->isThisDeclarationADefinition(); + return false; +} /// Starting at a given context (a Decl or DeclContext), look for a /// code context that is not a closure (a lambda, block, etc.). diff --git a/clang/test/SemaTemplate/friend-template.cpp b/clang/test/SemaTemplate/friend-template.cpp index e9b2b9b..1ed751b 100644 --- a/clang/test/SemaTemplate/friend-template.cpp +++ b/clang/test/SemaTemplate/friend-template.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s // PR5057 namespace test0 { namespace std { @@ -68,17 +68,12 @@ namespace test3 { Foo foo; template struct X2a; - - template struct X2b; + template struct X2b; // expected-note {{previous non-type template parameter with type 'int' is here}} template class X3 { template friend struct X2a; - - // FIXME: the redeclaration note ends up here because redeclaration - // lookup ends up finding the friend target from X3. - template friend struct X2b; // expected-error {{template non-type parameter has a different type 'long' in template redeclaration}} \ - // expected-note {{previous non-type template parameter with type 'int' is here}} + template friend struct X2b; // expected-error {{template non-type parameter has a different type 'long' in template redeclaration}} }; X3 x3i; // okay @@ -297,14 +292,11 @@ namespace PR12585 { int n = C::D().f(); struct F { - template struct G; + template struct G; // expected-note {{previous}} }; template struct H { - // FIXME: As with cases above, the note here is on an unhelpful declaration, - // and should point to the declaration of G within F. template friend struct F::G; // \ - // expected-error {{different type 'char' in template redeclaration}} \ - // expected-note {{previous}} + // expected-error {{different type 'char' in template redeclaration}} }; H h1; // ok H h2; // expected-note {{instantiation}} @@ -329,3 +321,11 @@ namespace rdar12350696 { foo(b); // expected-note {{in instantiation}} } } +namespace PR30994 { + void f(); + struct A { + [[deprecated]] friend void f() {} // \ + expected-note {{has been explicitly marked deprecated here}} + }; + void g() { f(); } // expected-warning {{is deprecated}} +}