Disable forward-declares for decls in inline namespaces
Technically users can forward-declare inline namespaces, e.g. namespace std { inline namespace __1 { template <class T> struct hash; } } but that would be both confusing and problematic: 1) The symbol is referred to as std::hash, but declared here with a name nobody should ever see. 2) When a new ABI version is added for std::hash, a new internal namespace -- e.g. __2 -- will be added, and std::hash and std::__1::hash no longer refer to the same symbol. As inline namespaces are intended primarily as a versioning feature for library authors, avoid trying to second-guess them and just require a full use for any decl inside an inline namespace. This fixes issue #713.
This commit is contained in:
parent
8353f98e6a
commit
613efed42e
|
@ -953,6 +953,16 @@ bool IsExplicitInstantiation(const clang::Decl* decl) {
|
|||
kind == clang::TSK_ExplicitInstantiationDefinition;
|
||||
}
|
||||
|
||||
bool IsInInlineNamespace(const Decl* decl) {
|
||||
const DeclContext* dc = decl->getDeclContext();
|
||||
for (; dc; dc = dc->getParent()) {
|
||||
if (dc->isInlineNamespace())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsForwardDecl(const NamedDecl* decl) {
|
||||
if (const auto* record_decl = dyn_cast<RecordDecl>(decl)) {
|
||||
|
||||
|
|
|
@ -597,6 +597,9 @@ bool IsFriendDecl(const clang::Decl* decl);
|
|||
// or definition.
|
||||
bool IsExplicitInstantiation(const clang::Decl* decl);
|
||||
|
||||
// Returns true if this decl is nested inside an inline namespace.
|
||||
bool IsInInlineNamespace(const clang::Decl* decl);
|
||||
|
||||
// Returns true if a named decl looks like a forward-declaration of a
|
||||
// class (rather than a definition, a friend declaration, or an 'in
|
||||
// place' declaration like 'struct Foo' in 'void MyFunc(struct Foo*);'
|
||||
|
|
|
@ -716,6 +716,10 @@ static void LogIncludeMapping(const string& reason, const OneUse& use) {
|
|||
namespace internal {
|
||||
|
||||
bool DeclCanBeForwardDeclared(const Decl* decl) {
|
||||
// Nothing inside an inline namespace can be forward-declared.
|
||||
if (IsInInlineNamespace(decl))
|
||||
return false;
|
||||
|
||||
// Class templates can always be forward-declared.
|
||||
if (isa<ClassTemplateDecl>(decl))
|
||||
return true;
|
||||
|
|
|
@ -158,6 +158,7 @@ class OneIwyuTest(unittest.TestCase):
|
|||
'implicit_ctor.cc': ['.'],
|
||||
'include_cycle.cc': ['.'],
|
||||
'include_with_using.cc': ['.'],
|
||||
'inline_namespace.cc': ['.'],
|
||||
'internal/internal_files.cc': ['.'],
|
||||
'iwyu_stricter_than_cpp.cc': ['.'],
|
||||
'keep_includes.c': ['.'],
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
//===--- inline_namespace-d1.h - test input file for iwyu -----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef INCLUDE_WHAT_YOU_USE_TESTS_CXX_INLINE_NAMESPACE_D1_H_
|
||||
#define INCLUDE_WHAT_YOU_USE_TESTS_CXX_INLINE_NAMESPACE_D1_H_
|
||||
|
||||
#include "tests/cxx/inline_namespace-i1.h"
|
||||
|
||||
#endif // INCLUDE_WHAT_YOU_USE_TESTS_CXX_INLINE_NAMESPACE_D1_H_
|
|
@ -0,0 +1,24 @@
|
|||
//===--- inline_namespace-i1.h - test input file for iwyu -----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef INCLUDE_WHAT_YOU_USE_TESTS_CXX_INLINE_NAMESPACE_I1_H_
|
||||
#define INCLUDE_WHAT_YOU_USE_TESTS_CXX_INLINE_NAMESPACE_I1_H_
|
||||
|
||||
namespace xyz {
|
||||
inline namespace v1 {
|
||||
|
||||
struct Foo {
|
||||
int value;
|
||||
};
|
||||
|
||||
} // namespace v1
|
||||
} // namespace xyz
|
||||
|
||||
#endif // INCLUDE_WHAT_YOU_USE_TESTS_CXX_INLINE_NAMESPACE_I1_H_
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
//===--- inline_namespace.cc - test input file for iwyu -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Tests that IWYU never considers a decl inside an inline namespace
|
||||
// forward-declarable, and that diagnostics never mention the inline namespace
|
||||
// name (xyz::v1).
|
||||
|
||||
#include "tests/cxx/inline_namespace.h"
|
||||
|
||||
// IWYU: xyz::Foo is...*inline_namespace-i1.h
|
||||
int Function(const xyz::Foo& foo) {
|
||||
// IWYU: xyz::Foo is...*inline_namespace-i1.h
|
||||
return foo.value;
|
||||
}
|
||||
|
||||
/**** IWYU_SUMMARY
|
||||
|
||||
(tests/cxx/inline_namespace.cc has correct #includes/fwd-decls)
|
||||
|
||||
***** IWYU_SUMMARY */
|
|
@ -0,0 +1,35 @@
|
|||
//===--- inline_namespace.h - test input file for iwyu --------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef INCLUDE_WHAT_YOU_USE_TESTS_CXX_INLINE_NAMESPACE_H_
|
||||
#define INCLUDE_WHAT_YOU_USE_TESTS_CXX_INLINE_NAMESPACE_H_
|
||||
|
||||
#include "tests/cxx/inline_namespace-d1.h"
|
||||
|
||||
// A forward-declare would typically be enough here, but the presence of the
|
||||
// inline namespace xyz::v1 disqualifies forward declaration, and promotes it to
|
||||
// a full use.
|
||||
|
||||
// IWYU: xyz::Foo is...*inline_namespace-i1.h
|
||||
int Function(const xyz::Foo& foo);
|
||||
|
||||
#endif // INCLUDE_WHAT_YOU_USE_TESTS_CXX_INLINE_NAMESPACE_H_
|
||||
|
||||
/**** IWYU_SUMMARY
|
||||
|
||||
tests/cxx/inline_namespace.h should add these lines:
|
||||
#include "tests/cxx/inline_namespace-i1.h"
|
||||
|
||||
tests/cxx/inline_namespace.h should remove these lines:
|
||||
- #include "tests/cxx/inline_namespace-d1.h" // lines XX-XX
|
||||
|
||||
The full include-list for tests/cxx/inline_namespace.h:
|
||||
#include "tests/cxx/inline_namespace-i1.h" // for Foo
|
||||
|
||||
***** IWYU_SUMMARY */
|
Loading…
Reference in New Issue