arphaman created this revision. arphaman added reviewers: rsmith, rjmccall. arphaman added a subscriber: cfe-commits. arphaman set the repository for this revision to rL LLVM.
This patch improves the "must have C++ linkage" error diagnostics for C++ by adding an additional note that points to the appropriate `extern "C"` linkage specifier. This patch covers the diagnostics for templates and literal operators, which AFAIK are the only declarations that emit this particular kind of error. Please let me know if you think there are errors for other C++ declarations that require similar changes. Repository: rL LLVM https://reviews.llvm.org/D26189 Files: include/clang/AST/DeclBase.h lib/AST/DeclBase.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplate.cpp test/CXX/over/over.oper/over.literal/p6.cpp test/SemaCXX/cxx0x-defaulted-functions.cpp test/SemaTemplate/class-template-decl.cpp
Index: test/SemaTemplate/class-template-decl.cpp =================================================================== --- test/SemaTemplate/class-template-decl.cpp +++ test/SemaTemplate/class-template-decl.cpp @@ -10,11 +10,11 @@ template<typename T> class C; } -extern "C" { +extern "C" { // expected-note {{extern "C" language linkage specification begins here}} template<typename T> class D; // expected-error{{templates must have C++ linkage}} } -extern "C" { +extern "C" { // expected-note 2 {{extern "C" language linkage specification begins here}} class PR17968 { template<typename T> class D; // expected-error{{templates must have C++ linkage}} template<typename T> void f(); // expected-error{{templates must have C++ linkage}} @@ -148,7 +148,7 @@ } extern "C" template <typename T> // expected-error{{templates must have C++ linkage}} -void DontCrashOnThis() { +void DontCrashOnThis() { // expected-note@-1 {{extern "C" language linkage specification begins here}} T &pT = T(); pT; } Index: test/SemaCXX/cxx0x-defaulted-functions.cpp =================================================================== --- test/SemaCXX/cxx0x-defaulted-functions.cpp +++ test/SemaCXX/cxx0x-defaulted-functions.cpp @@ -180,7 +180,7 @@ Outer<T>::Inner2<T>::~Inner2() = default; // expected-error {{nested name specifier 'Outer<T>::Inner2<T>::' for declaration does not refer into a class, class template or class template partial specialization}} expected-error {{only special member functions may be defaulted}} } -extern "C" { +extern "C" { // expected-note {{extern "C" language linkage specification begins here}} template<typename _Tp> // expected-error {{templates must have C++ linkage}} void PR13573(const _Tp&) = delete; } Index: test/CXX/over/over.oper/over.literal/p6.cpp =================================================================== --- test/CXX/over/over.oper/over.literal/p6.cpp +++ test/CXX/over/over.oper/over.literal/p6.cpp @@ -1,9 +1,11 @@ // RUN: %clang_cc1 -std=c++11 %s -verify +// expected-note@+1 {{extern "C" language linkage specification begins here}} extern "C" void operator "" _a(const char *); // expected-error {{must have C++ linkage}} extern "C" template<char...> void operator "" _b(); // expected-error {{must have C++ linkage}} +// expected-note@-1 {{extern "C" language linkage specification begins here}} -extern "C" { +extern "C" { // expected-note 4 {{extern "C" language linkage specification begins here}} void operator "" _c(const char *); // expected-error {{must have C++ linkage}} template<char...> void operator "" _d(); // expected-error {{must have C++ linkage}} namespace N { Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -5939,9 +5939,13 @@ // C++ [temp]p4: // A template [...] shall not have C linkage. DeclContext *Ctx = S->getEntity(); - if (Ctx && Ctx->isExternCContext()) - return Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage) - << TemplateParams->getSourceRange(); + if (Ctx && Ctx->isExternCContext()) { + Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage) + << TemplateParams->getSourceRange(); + if (const LinkageSpecDecl *LSD = Ctx->getExternCContext()) + Diag(LSD->getExternLoc(), diag::note_module_import_in_extern_c); + return true; + } Ctx = Ctx->getRedeclContext(); // C++ [temp]p2: Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -12757,6 +12757,9 @@ if (FnDecl->isExternC()) { Diag(FnDecl->getLocation(), diag::err_literal_operator_extern_c); + if (const LinkageSpecDecl *LSD = + FnDecl->getDeclContext()->getExternCContext()) + Diag(LSD->getExternLoc(), diag::note_module_import_in_extern_c); return true; } Index: lib/AST/DeclBase.cpp =================================================================== --- lib/AST/DeclBase.cpp +++ lib/AST/DeclBase.cpp @@ -992,6 +992,18 @@ return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_c); } +const LinkageSpecDecl *DeclContext::getExternCContext() const { + const DeclContext *DC = this; + while (DC->getDeclKind() != Decl::TranslationUnit) { + if (DC->getDeclKind() == Decl::LinkageSpec && + cast<LinkageSpecDecl>(DC)->getLanguage() == + clang::LinkageSpecDecl::lang_c) + return cast<LinkageSpecDecl>(DC); + DC = DC->getLexicalParent(); + } + return nullptr; +} + bool DeclContext::isExternCXXContext() const { return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_cxx); } Index: include/clang/AST/DeclBase.h =================================================================== --- include/clang/AST/DeclBase.h +++ include/clang/AST/DeclBase.h @@ -1334,6 +1334,9 @@ /// linkage specification context that specifies C linkage. bool isExternCContext() const; + /// \brief Retrieve the nearest enclosing C linkage specification context. + const LinkageSpecDecl *getExternCContext() const; + /// \brief Determines whether this context or some of its ancestors is a /// linkage specification context that specifies C++ linkage. bool isExternCXXContext() const;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits