]> granicus.if.org Git - clang/commitdiff
PR41817: Fix regression in r359260 that caused the MS compatibility
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 14 May 2019 00:27:16 +0000 (00:27 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 14 May 2019 00:27:16 +0000 (00:27 +0000)
extension allowing a "static" declaration to follow an "extern"
declaration to stop working.

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

lib/AST/Decl.cpp
test/CodeGen/ms-compat-extern-static.c [new file with mode: 0644]

index 4e42dd7d3bd47435efb22e188ea74cb1d2375b6b..1ca66cfb5f1692fb27177d0532e329aaf930e4d4 100644 (file)
@@ -613,12 +613,41 @@ static LinkageInfo getExternalLinkageFor(const NamedDecl *D) {
 static StorageClass getStorageClass(const Decl *D) {
   if (auto *TD = dyn_cast<TemplateDecl>(D))
     D = TD->getTemplatedDecl();
-  if (D) {
-    if (auto *VD = dyn_cast<VarDecl>(D))
-      return VD->getStorageClass();
-    if (auto *FD = dyn_cast<FunctionDecl>(D))
-      return FD->getStorageClass();
+  if (!D)
+    return SC_None;
+
+  if (auto *VD = dyn_cast<VarDecl>(D)) {
+    // Generally, the storage class is determined by the first declaration.
+    auto SC = VD->getCanonicalDecl()->getStorageClass();
+
+    // ... except that MSVC permits an 'extern' declaration to be redeclared
+    // 'static' as an extension.
+    if (SC == SC_Extern) {
+      for (auto *Redecl : VD->redecls()) {
+        if (Redecl->getStorageClass() == SC_Static)
+          return SC_Static;
+        if (Redecl->getStorageClass() != SC_Extern &&
+            !Redecl->isLocalExternDecl() && !Redecl->getFriendObjectKind())
+          break;
+      }
+    }
+    return SC;
   }
+
+  if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+    auto SC = FD->getCanonicalDecl()->getStorageClass();
+    if (SC == SC_Extern) {
+      for (auto *Redecl : FD->redecls()) {
+        if (Redecl->getStorageClass() == SC_Static)
+          return SC_Static;
+        if (Redecl->getStorageClass() != SC_Extern &&
+            !Redecl->isLocalExternDecl() && !Redecl->getFriendObjectKind())
+          break;
+      }
+    }
+    return SC;
+  }
+
   return SC_None;
 }
 
@@ -634,7 +663,7 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
   //   A name having namespace scope (3.3.6) has internal linkage if it
   //   is the name of
 
-  if (getStorageClass(D->getCanonicalDecl()) == SC_Static) {
+  if (getStorageClass(D) == SC_Static) {
     // - a variable, variable template, function, or function template
     //   that is explicitly declared static; or
     // (This bullet corresponds to C99 6.2.2p3.)
diff --git a/test/CodeGen/ms-compat-extern-static.c b/test/CodeGen/ms-compat-extern-static.c
new file mode 100644 (file)
index 0000000..2ad60ef
--- /dev/null
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -fms-extensions -triple x86_64-windows | FileCheck %s
+
+// CHECK: @n = internal global i32 1
+extern int n;
+static int n = 1;
+int *use = &n;
+
+// CHECK: define internal void @f(
+extern void f();
+static void f() {}
+void g() { return f(); }