]> granicus.if.org Git - clang/commitdiff
Add a note that points to the linkage specifier for the C++ linkage errors
authorAlex Lorenz <arphaman@gmail.com>
Wed, 2 Nov 2016 15:46:34 +0000 (15:46 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Wed, 2 Nov 2016 15:46:34 +0000 (15:46 +0000)
This commit improves the "must have C++ linkage" error diagnostics that are
emitted for C++ declarations like templates and literal operators by adding an
additional note that points to the appropriate extern "C" linkage specifier.

rdar://19021120

Differential Revision: https://reviews.llvm.org/D26189

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@285823 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclBase.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/DeclBase.cpp
lib/Sema/SemaDecl.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 3a80ff5b234e9254007f326b81991c75eeee36d5..5de1d0588e80eef3c1b13a90bb6dd475a381c893 100644 (file)
@@ -1334,6 +1334,9 @@ public:
   /// 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;
index e4290d8945aacd7a096b465de814a3c665b6792d..74fed48806a011a82e5bf93a61ae16e1bda7835d 100644 (file)
@@ -4502,6 +4502,8 @@ def err_extern_c_global_conflict : Error<
   "conflicts with declaration %select{in global scope|with C language linkage}0">;
 def note_extern_c_global_conflict : Note<
   "declared %select{in global scope|with C language linkage}0 here">;
+def note_extern_c_begins_here : Note<
+  "extern \"C\" language linkage specification begins here">;
 def warn_weak_import : Warning <
   "an already-declared variable is made a weak_import declaration %0">;
 def ext_static_non_static : Extension<
@@ -8605,8 +8607,6 @@ def ext_module_import_in_extern_c : ExtWarn<
   "import of C++ module '%0' appears within extern \"C\" language linkage "
   "specification">, DefaultError,
   InGroup<DiagGroup<"module-import-in-extern-c">>;
-def note_module_import_in_extern_c : Note<
-  "extern \"C\" language linkage specification begins here">;
 def err_module_import_not_at_top_level_fatal : Error<
   "import of module '%0' appears within %1">, DefaultFatal;
 def ext_module_import_not_at_top_level_noop : ExtWarn<
index 7e790cec68ade97833df8d315f85601cd63513c1..5d130acfbedfbe39cc44cbaf83d61e8d8f5155b1 100644 (file)
@@ -992,6 +992,18 @@ bool DeclContext::isExternCContext() const {
   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 1813aa0b64859a240375344e4b69a7e9d3e4875e..e20ae1a01510cde42d7719df62236fb68333027f 100644 (file)
@@ -15341,7 +15341,7 @@ static void checkModuleImportContext(Sema &S, Module *M,
   } else if (!M->IsExternC && ExternCLoc.isValid()) {
     S.Diag(ImportLoc, diag::ext_module_import_in_extern_c)
       << M->getFullModuleName();
-    S.Diag(ExternCLoc, diag::note_module_import_in_extern_c);
+    S.Diag(ExternCLoc, diag::note_extern_c_begins_here);
   }
 }
 
index 17d1978de030d4dfa068c0f921b54c847e6b70ac..fb3b7373978689ea1a059b5906bca0ad5a66ce5e 100644 (file)
@@ -12757,6 +12757,9 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
 
   if (FnDecl->isExternC()) {
     Diag(FnDecl->getLocation(), diag::err_literal_operator_extern_c);
+    if (const LinkageSpecDecl *LSD =
+            FnDecl->getDeclContext()->getExternCContext())
+      Diag(LSD->getExternLoc(), diag::note_extern_c_begins_here);
     return true;
   }
 
index 71b2153d05a019f407b59e57c1e5aae916de61c3..ce41a5eb74f6a515bd2a4bedadc219a69c86a22f 100644 (file)
@@ -5939,9 +5939,13 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
   // 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_extern_c_begins_here);
+    return true;
+  }
   Ctx = Ctx->getRedeclContext();
 
   // C++ [temp]p2:
index 6bfb8560d688935207fdf5171272332f5e02d216..9ecf9ccccb14c6bc191c7038d7441221caed050e 100644 (file)
@@ -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 f4bbce818d94fba3acc4ae767ca18b73fdaba260..f623dc765f88c0fedc6a11076505d22fbbf37ac7 100644 (file)
@@ -180,7 +180,7 @@ namespace PR14577 {
   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 63482d84df0c9c4c431f61045235c786e68e6f54..2e36cae14f600776d079d3210011dc056cd13a63 100644 (file)
@@ -10,11 +10,11 @@ namespace N {
   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 @@ namespace redecl {
 }
 
 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;
 }