diff options
-rw-r--r-- | compilerplugins/clang/externvar.cxx | 104 | ||||
-rw-r--r-- | compilerplugins/clang/test/externvar.cxx | 61 | ||||
-rw-r--r-- | compilerplugins/clang/test/externvar.hxx | 27 | ||||
-rw-r--r-- | solenv/CompilerTest_compilerplugins_clang.mk | 1 |
4 files changed, 193 insertions, 0 deletions
diff --git a/compilerplugins/clang/externvar.cxx b/compilerplugins/clang/externvar.cxx new file mode 100644 index 000000000000..9569a3de37d2 --- /dev/null +++ b/compilerplugins/clang/externvar.cxx @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "check.hxx" +#include "plugin.hxx" + +// Find variable declarations at namespace scope that need not have external +// linkage. + +namespace { + +// It looks like Clang wrongly implements DR 4 +// (<http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#4>) and treats +// a variable declared in an 'extern "..." {...}'-style linkage-specification as +// if it contained the 'extern' specifier: +bool hasExternalLinkage(VarDecl const * decl) { + if (decl->getLinkageAndVisibility().getLinkage() != ExternalLinkage) { + return false; + } + for (auto ctx = decl->getLexicalDeclContext(); + ctx->getDeclKind() != Decl::TranslationUnit; + ctx = ctx->getLexicalParent()) + { + if (auto ls = dyn_cast<LinkageSpecDecl>(ctx)) { + if (!ls->hasBraces()) { + return true; + } + if (auto prev = decl->getPreviousDecl()) { + return hasExternalLinkage(prev); + } + return !decl->isInAnonymousNamespace(); + } + } + return true; +} + +class ExternVar: public RecursiveASTVisitor<ExternVar>, public loplugin::Plugin +{ +public: + explicit ExternVar(InstantiationData const & data): Plugin(data) {} + + void run() override + { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); } + + bool VisitVarDecl(VarDecl const * decl) { + if (ignoreLocation(decl)) { + return true; + } + if (decl->isStaticDataMember()) { + return true; + } + if (!(decl->isFirstDecl() + && compiler.getSourceManager().isInMainFile(decl->getLocation()) + && hasExternalLinkage(decl))) + { + return true; + } + auto def = decl->getDefinition(); + if (def == nullptr) { + // Code like + // + // namespace { extern int v; } + // int f() { return sizeof(v); } + // + // is already handled by Clang itself with an error "variable 'v' is + // not needed and will not be emitted" + return true; + } + report( + DiagnosticsEngine::Warning, + "variable with external linkage not declared in an include file", + def->getLocation()) + << def->getSourceRange(); + report( + DiagnosticsEngine::Note, + ("should either have internal linkage or be declared in an include" + " file"), + def->getLocation()) + << def->getSourceRange(); + for (auto prev = def;;) { + prev = prev->getPreviousDecl(); + if (prev == nullptr) { + break; + } + report( + DiagnosticsEngine::Note, "previously declared here", + prev->getLocation()) + << prev->getSourceRange(); + } + return true; + } +}; + +loplugin::Plugin::Registration<ExternVar> X("externvar"); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/externvar.cxx b/compilerplugins/clang/test/externvar.cxx new file mode 100644 index 000000000000..51f743fbba83 --- /dev/null +++ b/compilerplugins/clang/test/externvar.cxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <externvar.hxx> + +int v1; +int v2; // expected-error {{variable with external linkage not declared in an include file [loplugin:externvar]}} expected-note {{should either have internal linkage or be declared in an include file [loplugin:externvar]}} +static int v3; +int const v4 = 0; + +extern int v5; // expected-note {{previously declared here [loplugin:externvar]}} +int v5; // expected-error {{variable with external linkage not declared in an include file [loplugin:externvar]}} expected-note {{should either have internal linkage or be declared in an include file [loplugin:externvar]}} + +extern "C" int v6; // expected-note {{previously declared here [loplugin:externvar]}} +int v6; // expected-error {{variable with external linkage not declared in an include file [loplugin:externvar]}} expected-note {{should either have internal linkage or be declared in an include file [loplugin:externvar]}} +extern "C" { int v7; } // expected-error {{variable with external linkage not declared in an include file [loplugin:externvar]}} expected-note {{should either have internal linkage or be declared in an include file [loplugin:externvar]}} + +namespace { + +int u1; +static int u2; +extern "C" int u3; // expected-note {{previously declared here [loplugin:externvar]}} +int u3; // expected-error {{variable with external linkage not declared in an include file [loplugin:externvar]}} expected-note {{should either have internal linkage or be declared in an include file [loplugin:externvar]}} +extern "C" { int u4; } + +} + +namespace N { + +int v1; +int v2; // expected-error {{variable with external linkage not declared in an include file [loplugin:externvar]}} expected-note {{should either have internal linkage or be declared in an include file [loplugin:externvar]}} +static int v3; + +} + +struct S { + static int f() { + static int s = 0; + return s; + } + + static int m; +}; + +int S::m = 0; + +int f(int a) { + static int s = 0; + ++s; + int b = a + s + v1 + v2 + v3 + v4 + v5 + v6 + v7 + u1 + u2 + u3 + u4 + N::v1 + + N::v2 + N::v3 + S::f(); + return b; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/externvar.hxx b/compilerplugins/clang/test/externvar.hxx new file mode 100644 index 000000000000..225f1ee59fd0 --- /dev/null +++ b/compilerplugins/clang/test/externvar.hxx @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INClUDED_COMPILERPLUGINS_CLANG_TEST_EXTERNVAR_HXX +#define INClUDED_COMPILERPLUGINS_CLANG_TEST_EXTERNVAR_HXX + +extern int v1; + +namespace N { + +extern int v1; + +} + +struct S; + +int f(int a); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/solenv/CompilerTest_compilerplugins_clang.mk b/solenv/CompilerTest_compilerplugins_clang.mk index a4c0a15e6b8e..4934ae28ea6e 100644 --- a/solenv/CompilerTest_compilerplugins_clang.mk +++ b/solenv/CompilerTest_compilerplugins_clang.mk @@ -11,6 +11,7 @@ $(eval $(call gb_CompilerTest_CompilerTest,compilerplugins_clang)) $(eval $(call gb_CompilerTest_add_exception_objects,compilerplugins_clang, \ compilerplugins/clang/test/datamembershadow \ + compilerplugins/clang/test/externvar \ compilerplugins/clang/test/finalprotected \ compilerplugins/clang/test/passstuffbyref \ compilerplugins/clang/test/oslendian-1 \ |