diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1635,6 +1635,19 @@ // A redeclaration of an entity X is implicitly exported if X was introduced by // an exported declaration; otherwise it shall not be exported. bool Sema::CheckRedeclarationExported(NamedDecl *New, NamedDecl *Old) { + // [module.interface]p1: + // An export-declaration shall inhabit a namespace scope. + // + // So it is meaningless to talk about redeclaration which is not at namespace + // scope. + if (!New->getLexicalDeclContext() + ->getNonTransparentContext() + ->isFileContext() || + !Old->getLexicalDeclContext() + ->getNonTransparentContext() + ->isFileContext()) + return false; + bool IsNewExported = New->isInExportDeclContext(); bool IsOldExported = Old->isInExportDeclContext(); diff --git a/clang/test/CXX/module/module.interface/p6.cpp b/clang/test/CXX/module/module.interface/p6.cpp --- a/clang/test/CXX/module/module.interface/p6.cpp +++ b/clang/test/CXX/module/module.interface/p6.cpp @@ -91,3 +91,24 @@ T TemplVar; // expected-note {{previous declaration is here}} export template T TemplVar; // expected-error {{cannot export redeclaration 'TemplVar' here since the previous declaration is not exported}} + +// Test the compiler wouldn't complain about the redeclaration of friend in exported class. +namespace Friend { +template +class bar; +class gua; +template +void hello(); +void hi(); +export class foo; +bool operator<(const foo &a, const foo &b); +export class foo { + template + friend class bar; + friend class gua; + template + friend void hello(); + friend void hi(); + friend bool operator<(const foo &a, const foo &b); +}; +} // namespace Friend