[PATCH] PR17337: Retained language linkage

Alp Toker alp at nuanti.com
Tue Oct 22 10:46:46 PDT 2013


Hello Richard,

With this patch, friend function declarations will retain the language
linkage specified for previous declarations instead of emitting an error
diagnostic.

The feature is known to be compatible with GCC and MSVC and permits a
language to be specified indirectly where it cannot otherwise be written
directly in class scope.

Further to the previous patch, this feature is now a clang extension so
warnings can be enabled/disabled with a -Wretained-language-linkage flag
while we seek clarifications to the language standard. Tests have been
moved to SemaCXX/linkage-spec.cpp.

Alp.

-- 
http://www.nuanti.com
the browser experts

-------------- next part --------------
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 415c4b2..bf2b4a8 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3573,6 +3573,9 @@ def err_static_non_static : Error<
   "static declaration of %0 follows non-static declaration">;
 def err_different_language_linkage : Error<
   "declaration of %0 has a different language linkage">;
+def ext_retained_language_linkage : Extension<
+  "friend function %0 retaining previous language linkage is an extension">,
+  InGroup<DiagGroup<"retained-language-linkage">>;
 def err_extern_c_global_conflict : Error<
   "declaration of %1 %select{with C language linkage|in global scope}0 "
   "conflicts with declaration %select{in global scope|with C language linkage}0">;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 325366b..1b7b1e2 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2577,9 +2577,22 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
     }
 
     if (haveIncompatibleLanguageLinkages(Old, New)) {
-      Diag(New->getLocation(), diag::err_different_language_linkage) << New;
-      Diag(Old->getLocation(), PrevDiag);
-      return true;
+      // As a special case, retain the language linkage from previous
+      // declarations of a friend function as an extension.
+      //
+      // This liberal interpretation of C++ [class.friend]p3 matches GCC/MSVC
+      // and is useful because there's otherwise no way to specify language
+      // linkage within class scope.
+      //
+      // The friend object kind isn't yet complete so check IDNS directly.
+      if (New->getIdentifierNamespace() & Decl::IDNS_OrdinaryFriend) {
+        Diag(New->getLocation(), diag::ext_retained_language_linkage) << New;
+        Diag(Old->getLocation(), PrevDiag);
+      } else {
+        Diag(New->getLocation(), diag::err_different_language_linkage) << New;
+        Diag(Old->getLocation(), PrevDiag);
+        return true;
+      }
     }
 
     if (OldQTypeForComparison == NewQType)
diff --git a/test/SemaCXX/linkage-spec.cpp b/test/SemaCXX/linkage-spec.cpp
index bdc217d..1598d0e 100644
--- a/test/SemaCXX/linkage-spec.cpp
+++ b/test/SemaCXX/linkage-spec.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wretained-language-linkage -DW_RETAINED_LANGUAGE_LINKAGE  %s
 extern "C" {
   extern "C" void f(int);
 }
@@ -154,3 +155,21 @@ void bar_pr7927() {
   ::f_pr7927(E_7927);
   ::f_pr7927(0);
 }
+
+namespace PR17337 {
+  extern "C++" {
+    class Foo;
+    extern "C" int bar3(Foo *y);
+    class Foo {
+      int x;
+      friend int bar3(Foo *y);
+#ifdef W_RETAINED_LANGUAGE_LINKAGE
+// expected-note at -5 {{previous declaration is here}}
+// expected-warning at -3 {{retaining previous language linkage}}
+#endif
+    };
+    extern "C" int bar3(Foo *y) {
+      return y->x;
+    }
+  }
+}


More information about the cfe-commits mailing list