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

Reply via email to