llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-systemz

Author: Sean Perry (perry-ca)

<details>
<summary>Changes</summary>

Implement the _Export keyword that is used on z/OS to indicate that a symbol 
with external linkage is to be exported from the shared library.  In the XL 
C/C++ compiler this keyword is used only in C++ source code.  That is being 
extended to include C source as well in this PR.

This code was originally in PR 
https://github.com/llvm/llvm-project/pull/111035.  I have split it out into a 
separate PR so the code for `#pragma export` is in one PR and the code for 
`_Export` keyword is in another.  See that original PR for earlier comments.

For reference, the XL documentation for _Export: 
https://www.ibm.com/docs/en/zos/3.1.0?topic=specifiers-export-function-specifier-c-only

---

Patch is 20.71 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/140944.diff


18 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+5) 
- (modified) clang/include/clang/Basic/Attr.td (+6) 
- (modified) clang/include/clang/Basic/AttrDocs.td (+33) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2) 
- (modified) clang/include/clang/Basic/TokenKinds.def (+3) 
- (modified) clang/include/clang/Sema/DeclSpec.h (+34-4) 
- (modified) clang/include/clang/Sema/Sema.h (+2) 
- (modified) clang/lib/Driver/ToolChains/ZOS.cpp (+4) 
- (modified) clang/lib/Parse/ParseDecl.cpp (+15) 
- (modified) clang/lib/Parse/ParseDeclCXX.cpp (+6) 
- (modified) clang/lib/Sema/DeclSpec.cpp (+6) 
- (modified) clang/lib/Sema/SemaDecl.cpp (+21) 
- (modified) clang/lib/Sema/SemaDeclAttr.cpp (+9) 
- (added) clang/test/CodeGen/attr-export.c (+23) 
- (added) clang/test/CodeGen/attr-export.cpp (+59) 
- (added) clang/test/Sema/attr-export-failing.cpp (+4) 
- (added) clang/test/Sema/zos-export.c (+25) 
- (added) clang/test/Sema/zos-export.cpp (+44) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ad8409397ff8a..8abfd60caedbc 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -879,6 +879,11 @@ WebAssembly Support
 AVR Support
 ^^^^^^^^^^^
 
+SystemZ Support
+^^^^^^^^^^^^^^^
+
+- Add support for `_Export` keyword for z/OS
+
 DWARF Support in Clang
 ----------------------
 
diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index a6a7482a94a29..7bbaaa53e275b 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4267,6 +4267,12 @@ def Thread : Attr {
   let Subjects = SubjectList<[Var]>;
 }
 
+def zOSExport : InheritableAttr {
+  let Spellings = [CustomKeyword<"_Export">];
+  let Subjects = SubjectList<[Function, Var, CXXRecord]>;
+  let Documentation = [zOSExportDocs];
+}
+
 def Win64 : IgnoredAttr {
   let Spellings = [CustomKeyword<"__w64">];
   let LangOpts = [MicrosoftExt];
diff --git a/clang/include/clang/Basic/AttrDocs.td 
b/clang/include/clang/Basic/AttrDocs.td
index 65d66dd398ad1..3beb38552df05 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -242,6 +242,39 @@ members, and static locals.
   }];
 }
 
+def zOSExportDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+Use the ``_Export`` keyword on a function or external variable to declare
+that it is to be exported (made available to other modules).  A symbol needs 
to be
+declared exported on or before the definition of the symbol.  The ``_Export``
+keyword must immediately precede the declaration name in the declarator.
+For example:
+
+.. code-block:: c
+
+  int _Export func(float);
+  int (*_Export funcPtr)(float);
+
+The first statement exports the function ``func``, if ``func`` is defined in 
the
+translation unit after this declaration.
+
+All of the static data members and member functions of a class or struct and 
its vague
+linkage objects (vtable, typeinfo, typeinfo name) can be exported
+by including ``_Export`` in tag of the class during the class definition or 
forward
+declaration of the class.
+
+.. code-block:: c++
+
+  class _Export C {
+    int func();
+  };
+
+Select members of a class can be exported by using the ``_Export`` keyword on
+declaration within the class or definition of the member.
+  }];
+}
+
 def NoEscapeDocs : Documentation {
   let Category = DocCatVariable;
   let Content = [{
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 66f9480d99380..8d84d0bb698b3 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9655,6 +9655,8 @@ def warn_redefine_extname_not_applied : Warning<
   "#pragma redefine_extname is applicable to external C declarations only; "
   "not applied to %select{function|variable}0 %1">,
   InGroup<Pragmas>;
+def err_cannot_be_exported : Error<
+  "needs to have external linkage to be '_Export` qualified">;
 } // End of general sema category.
 
 // inline asm.
diff --git a/clang/include/clang/Basic/TokenKinds.def 
b/clang/include/clang/Basic/TokenKinds.def
index 94e72fea56a68..d0cb1aa2d7844 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -353,6 +353,9 @@ KEYWORD(__ptrauth                   , KEYALL)
 // C2y
 UNARY_EXPR_OR_TYPE_TRAIT(_Countof, CountOf, KEYNOCXX)
 
+// z/OS specific keywords
+KEYWORD(_Export                     , KEYZOS)
+
 // C++ 2.11p1: Keywords.
 KEYWORD(asm                         , KEYCXX|KEYGNU)
 KEYWORD(bool                        , BOOLSUPPORT|KEYC23)
diff --git a/clang/include/clang/Sema/DeclSpec.h 
b/clang/include/clang/Sema/DeclSpec.h
index 6c4a32c4ac2f0..58a69d274a02e 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -397,6 +397,8 @@ class DeclSpec {
   unsigned FS_virtual_specified : 1;
   LLVM_PREFERRED_TYPE(bool)
   unsigned FS_noreturn_specified : 1;
+  LLVM_PREFERRED_TYPE(bool)
+  unsigned ExportSpecified : 1; // z/OS extension
 
   // friend-specifier
   LLVM_PREFERRED_TYPE(bool)
@@ -443,6 +445,7 @@ class DeclSpec {
   SourceLocation FS_forceinlineLoc;
   SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;
   SourceLocation TQ_pipeLoc;
+  SourceLocation ExportLoc;
 
   WrittenBuiltinSpecs writtenBS;
   void SaveWrittenBuiltinSpecs();
@@ -491,9 +494,9 @@ class DeclSpec {
         TypeSpecPipe(false), TypeSpecSat(false), ConstrainedAuto(false),
         TypeQualifiers(TQ_unspecified), FS_inline_specified(false),
         FS_forceinline_specified(false), FS_virtual_specified(false),
-        FS_noreturn_specified(false), FriendSpecifiedFirst(false),
-        ConstexprSpecifier(
-            static_cast<unsigned>(ConstexprSpecKind::Unspecified)),
+        FS_noreturn_specified(false), ExportSpecified(false),
+        FriendSpecifiedFirst(false), ConstexprSpecifier(static_cast<unsigned>(
+                                         ConstexprSpecKind::Unspecified)),
         Attrs(attrFactory), writtenBS(), ObjCQualifiers(nullptr) {}
 
   // storage-class-specifier
@@ -660,6 +663,9 @@ class DeclSpec {
   bool isNoreturnSpecified() const { return FS_noreturn_specified; }
   SourceLocation getNoreturnSpecLoc() const { return FS_noreturnLoc; }
 
+  bool isExportSpecified() const { return ExportSpecified; }
+  SourceLocation getExportSpecLoc() const { return ExportLoc; }
+
   void ClearFunctionSpecs() {
     FS_inline_specified = false;
     FS_inlineLoc = SourceLocation();
@@ -810,6 +816,8 @@ class DeclSpec {
   bool setFunctionSpecNoreturn(SourceLocation Loc, const char *&PrevSpec,
                                unsigned &DiagID);
 
+  bool setExportSpec(SourceLocation Loc);
+
   bool SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
                      unsigned &DiagID);
   bool setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec,
@@ -1955,6 +1963,10 @@ class Declarator {
   LLVM_PREFERRED_TYPE(bool)
   unsigned InlineStorageUsed : 1;
 
+  /// Indicates whether this is set as _Export.
+  LLVM_PREFERRED_TYPE(bool)
+  unsigned ExportSpecified : 1; // z/OS extension
+
   /// Indicates whether this declarator has an initializer.
   LLVM_PREFERRED_TYPE(bool)
   unsigned HasInitializer : 1;
@@ -2001,6 +2013,9 @@ class Declarator {
   /// this declarator as a parameter pack.
   SourceLocation EllipsisLoc;
 
+  /// The source location of the _Export keyword on this declarator.
+  SourceLocation ExportLoc;
+
   Expr *PackIndexingExpr;
 
   friend struct DeclaratorChunk;
@@ -2030,7 +2045,8 @@ class Declarator {
                                    FunctionDefinitionKind::Declaration)),
         Redeclaration(false), Extension(false), ObjCIvar(false),
         ObjCWeakProperty(false), InlineStorageUsed(false),
-        HasInitializer(false), Attrs(DS.getAttributePool().getFactory()),
+        ExportSpecified(false), HasInitializer(false),
+        Attrs(DS.getAttributePool().getFactory()),
         DeclarationAttrs(DeclarationAttrs), AsmLabel(nullptr),
         TrailingRequiresClause(nullptr),
         InventedTemplateParameterList(nullptr) {
@@ -2109,6 +2125,18 @@ class Declarator {
       Range.setEnd(SR.getEnd());
   }
 
+  /// Set this declarator as _Export.
+  void SetExport(SourceLocation Loc) {
+    ExportSpecified = true;
+    ExportLoc = Loc;
+  }
+
+  /// Whether this declarator is marked as _Export.
+  bool IsExport() const { return ExportSpecified; }
+
+  /// Get the location of the _Export keyword.
+  SourceLocation getExportLoc() const { return ExportLoc; }
+
   /// Reset the contents of this Declarator.
   void clear() {
     SS.clear();
@@ -2125,8 +2153,10 @@ class Declarator {
     HasInitializer = false;
     ObjCIvar = false;
     ObjCWeakProperty = false;
+    ExportSpecified = false;
     CommaLoc = SourceLocation();
     EllipsisLoc = SourceLocation();
+    ExportLoc = SourceLocation();
     PackIndexingExpr = nullptr;
   }
 
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index a994b845e11fc..a973f116440ff 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4871,6 +4871,8 @@ class Sema final : public SemaBase {
                           TypeVisibilityAttr::VisibilityType Vis);
   VisibilityAttr *mergeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI,
                                       VisibilityAttr::VisibilityType Vis);
+  void mergeVisibilityType(Decl *D, SourceLocation Loc,
+                           VisibilityAttr::VisibilityType Type);
   SectionAttr *mergeSectionAttr(Decl *D, const AttributeCommonInfo &CI,
                                 StringRef Name);
 
diff --git a/clang/lib/Driver/ToolChains/ZOS.cpp 
b/clang/lib/Driver/ToolChains/ZOS.cpp
index c5ad3ef1b00f1..371623b83abd3 100644
--- a/clang/lib/Driver/ToolChains/ZOS.cpp
+++ b/clang/lib/Driver/ToolChains/ZOS.cpp
@@ -37,6 +37,10 @@ void ZOS::addClangTargetOptions(const ArgList &DriverArgs,
                                 options::OPT_fno_aligned_allocation))
     CC1Args.push_back("-faligned-alloc-unavailable");
 
+  if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
+                         options::OPT_fvisibility_ms_compat))
+    CC1Args.push_back("-fvisibility=hidden");
+
   if (DriverArgs.hasFlag(options::OPT_fxl_pragma_pack,
                          options::OPT_fno_xl_pragma_pack, true))
     CC1Args.push_back("-fxl-pragma-pack");
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 7a87cd2e340cc..3928062079cfc 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4217,6 +4217,11 @@ void Parser::ParseDeclarationSpecifiers(
       isInvalid = DS.setFunctionSpecNoreturn(Loc, PrevSpec, DiagID);
       break;
 
+    case tok::kw__Export:
+      // _Export keyword is part of the declarator id
+      goto DoneWithDeclSpec;
+      break;
+
     // friend
     case tok::kw_friend:
       if (DSContext == DeclSpecContext::DSC_class) {
@@ -6418,6 +6423,16 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
 
   tok::TokenKind Kind = Tok.getKind();
 
+  if (Kind == tok::kw__Export) {
+    SourceLocation loc = ConsumeToken();
+    D.SetExport(loc);
+    D.SetRangeEnd(loc);
+
+    if (DirectDeclParser)
+      (this->*DirectDeclParser)(D);
+    return;
+  }
+
   if (D.getDeclSpec().isTypeSpecPipe() && !isPipeDeclarator(D)) {
     DeclSpec DS(AttrFactory);
     ParseTypeQualifierListOpt(DS);
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 316bc30edf1f0..8d991ddc85e93 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1588,6 +1588,12 @@ void Parser::ParseClassSpecifier(tok::TokenKind 
TagTokKind,
   // If attributes exist after tag, parse them.
   for (;;) {
     MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs);
+    if (Tok.is(tok::kw__Export)) {
+      SourceLocation loc = ConsumeToken();
+      DS.setExportSpec(loc);
+      continue;
+    }
+
     // Parse inheritance specifiers.
     if (Tok.isOneOf(tok::kw___single_inheritance,
                     tok::kw___multiple_inheritance,
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index ee5a862c32509..e1cafc3d0f977 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -1104,6 +1104,12 @@ bool DeclSpec::setFunctionSpecNoreturn(SourceLocation 
Loc,
   return false;
 }
 
+bool DeclSpec::setExportSpec(SourceLocation Loc) {
+  ExportSpecified = true;
+  ExportLoc = Loc;
+  return false;
+}
+
 bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
                              unsigned &DiagID) {
   if (isFriendSpecified()) {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index cb81ac889e480..2cbb7507795a0 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -5175,6 +5175,9 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, 
AccessSpecifier AS,
   assert(EllipsisLoc.isInvalid() &&
          "Friend ellipsis but not friend-specified?");
 
+  if (DS.isExportSpecified())
+    mergeVisibilityType(Tag, DS.getExportSpecLoc(), VisibilityAttr::Default);
+
   // Track whether this decl-specifier declares anything.
   bool DeclaresAnything = true;
 
@@ -6515,6 +6518,9 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
   if (!New)
     return nullptr;
 
+  if (D.IsExport())
+    mergeVisibilityType(New, D.getExportLoc(), VisibilityAttr::Default);
+
   warnOnCTypeHiddenInCPlusPlus(New);
 
   // If this has an identifier and is not a function template specialization,
@@ -6754,6 +6760,9 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, 
DeclContext* DC,
     return nullptr;
   }
 
+  if (D.IsExport())
+    Diag(D.getName().StartLocation, diag::err_cannot_be_exported);
+
   TypedefDecl *NewTD = ParseTypedefDecl(S, D, TInfo->getType(), TInfo);
   if (!NewTD) return nullptr;
 
@@ -8213,6 +8222,9 @@ NamedDecl *Sema::ActOnVariableDeclarator(
 
   ProcessPragmaWeak(S, NewVD);
 
+  if (D.IsExport() && !NewVD->hasExternalFormalLinkage())
+    Diag(D.getIdentifierLoc(), diag::err_cannot_be_exported);
+
   // If this is the first declaration of an extern C variable, update
   // the map of such variables.
   if (NewVD->isFirstDecl() && !NewVD->isInvalidDecl() &&
@@ -10864,6 +10876,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, 
DeclContext *DC,
   ProcessPragmaWeak(S, NewFD);
   checkAttributesAfterMerging(*this, *NewFD);
 
+  if (D.IsExport() && !NewFD->hasExternalFormalLinkage())
+    Diag(D.getIdentifierLoc(), diag::err_cannot_be_exported);
+
   AddKnownFunctionAttributes(NewFD);
 
   if (NewFD->hasAttr<OverloadableAttr>() &&
@@ -15423,6 +15438,9 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator 
&D,
   if (getLangOpts().OpenCL)
     deduceOpenCLAddressSpace(New);
 
+  if (D.IsExport())
+    Diag(D.getIdentifierLoc(), diag::err_cannot_be_exported);
+
   return New;
 }
 
@@ -19005,6 +19023,9 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, 
QualType T,
       PPC().CheckPPCMMAType(T, NewFD->getLocation()))
     NewFD->setInvalidDecl();
 
+  if (D && D->IsExport())
+    Diag(D->getIdentifierLoc(), diag::err_cannot_be_exported);
+
   NewFD->setAccess(AS);
   return NewFD;
 }
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 4d7f0455444f1..c1bbd2127ea03 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -2632,6 +2632,15 @@ static void handleExternalSourceSymbolAttr(Sema &S, Decl 
*D,
       S.Context, AL, Language, DefinedIn, IsGeneratedDeclaration, USR));
 }
 
+void Sema::mergeVisibilityType(Decl *D, SourceLocation Loc,
+                               VisibilityAttr::VisibilityType Value) {
+  if (VisibilityAttr *Attr = D->getAttr<VisibilityAttr>()) {
+    if (Attr->getVisibility() != Value)
+      Diag(Loc, diag::err_mismatched_visibility);
+  } else
+    D->addAttr(VisibilityAttr::CreateImplicit(Context, Value));
+}
+
 template <class T>
 static T *mergeVisibilityAttr(Sema &S, Decl *D, const AttributeCommonInfo &CI,
                               typename T::VisibilityType value) {
diff --git a/clang/test/CodeGen/attr-export.c b/clang/test/CodeGen/attr-export.c
new file mode 100644
index 0000000000000..aae0562c1890c
--- /dev/null
+++ b/clang/test/CodeGen/attr-export.c
@@ -0,0 +1,23 @@
+// REQUIRES: systemz-registered-target
+// RUN: %clang --target=s390x-none-zos -S -emit-llvm %s -o - | FileCheck %s
+
+// Check the variables
+// CHECK: @func_ptr = global ptr null, align 8
+// CHECK: @var1 = global i32 0, align 4
+// CHECK: @var2 = hidden global i32 0, align 4
+// CHECK: @var3 = global i32 0, align 4
+// CHECK: @var4 = hidden global i32 0, align 4
+// CHECK: @var5 = global i32 0, align 4
+
+// Check the functions
+// CHECK: define void @foo1
+// CHECK: define hidden void @foo2
+
+int _Export var1;
+int var2;
+int _Export var3, var4, _Export var5;
+
+void _Export foo1(){};
+void foo2(){};
+
+int (*_Export func_ptr)(void) = 0;
diff --git a/clang/test/CodeGen/attr-export.cpp 
b/clang/test/CodeGen/attr-export.cpp
new file mode 100644
index 0000000000000..b5da80356ffda
--- /dev/null
+++ b/clang/test/CodeGen/attr-export.cpp
@@ -0,0 +1,59 @@
+// REQUIRES: systemz-registered-target
+// RUN: %clangxx --target=s390x-none-zos -S -emit-llvm %s -o - | FileCheck %s
+
+// Check the variables
+// CHECK: @var1 = global i32 0, align 4
+// CHECK: @var2 = hidden global i32 0, align 4
+// CHECK: @var3 = global i32 0, align 4
+// CHECK: @var4 = hidden global i32 0, align 4
+// CHECK: @var5 = global i32 0, align 4
+// CHECK: @obj1 = global %class.class1 zeroinitializer, align 2
+// CHECK: @obj2 = hidden global %class.class1 zeroinitializer, align 2
+// CHECK: @func_ptr = global ptr null, align 8
+// CHECK: @p2m = global i64 -1, align 8
+
+// Check the functions
+// CHECK: define void @_Z4foo1v
+// CHECK: define hidden void @_Z4foo2v
+// CHECK: define void @_ZN6class13fooEv
+// CHECK: define hidden void @_ZN6class23fooEv
+// CHECK: define hidden void @_ZN6class33fooEv
+// CHECK: define void @_ZN6class33barEv
+
+int _Export var1;
+int var2;
+int _Export var3, var4, _Export var5;
+
+void _Export foo1(){};
+void foo2(){};
+
+class _Export class1 {
+public:
+  void foo();
+};
+
+class class2 {
+public:
+  void foo();
+};
+
+void class1::foo(){};
+
+void class2::foo(){};
+
+class1 _Export obj1;
+class1 obj2;
+
+class class3 {
+public:
+  int mbr;
+  void foo();
+  void _Export bar();
+};
+
+void class3::foo() {};
+void class3::bar() {};
+
+int (*_Export func_ptr)(void) = 0;
+
+int class3::* _Export p2m = 0;
diff --git a/clang/test/Sema/attr-export-failing.cpp 
b/clang/test/Sema/attr-export-failing.cpp
new file mode 100644
index 0000000000000..14c22c96f2f1f
--- /dev/null
+++ b/clang/test/Sema/attr-export-failing.cpp
@@ -0,0 +1,4 @@
+// REQUIRES: systemz-registered-target
+// RUN: %clang_cc1 -triple s390x-none-zos -fzos-extensions %s -fsyntax-only 
-verify
+__attribute__((visibility("hidden"))) int _Export i; // expected-error 
{{visibility does not match previous declaration}}
+class __attribute__((visibility("hidden"))) _Export C; // expected-error 
{{visibility does not match previous declaration}}
diff --git a/clang/test/Sema/zos-export.c b/clang/test/Sema/zos-export.c
new file mode 100644
index 0000000000000..64aeefd063411
--- /dev/null
+++ b/clang/test/Sema/zos-export.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple s390x-ibm-zos %s -fsyntax-only -verify
+
+typedef int _Export ty; //expected-error {{needs to have external linkage to 
be '_Export` qualified}}
+ty x;
+int f(int _Export argument); //expected-error {{needs to have external linkage 
to be '_Export` qualified}}
+static int _Export file_scope_static; //expected-error {{needs to have 
external linkage to be '_Export` qualified}}
+struct S {
+  int _Export nonstaticdatamember; //expected-error {{needs to have external 
linkage to be '_Export` qualified}}
+};
+void g() {
+  int _Export automatic; //expected-error {{needs to have external linkage to 
be '_Export` qualified}}
+}
+
+static void _Export static_func() { //expected-error {{needs to have external 
linkage to be '_Export` qualified}}
+}
+
+void _Export h() {
+  static_func();
+}
+
+void j() {
+  static int _Export sl = 0; //expected-error {{needs to have external linkage 
to be '_Export` qualified}}
+}
+
+int _Export file_scope;
diff --git a/clang/test/Sema/zos-export.cpp b/clang/test/Sema/zos-export.cpp
new file mode 100644
index 0000000000000..42be5327e28a5
--- /dev/null
+++ b/clang/test/Sema/zos-export.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -triple s390x-ibm-zos %s -fsyntax-only -verify
+
+typedef int _Export ty; //expected-error {{needs to have external linkage to 
be '_Export` qualified}}
+ty typedef_var;
+int f(int _Export argument); //expected-error {{needs to have external linkage 
to be '_Export` qualified}}
+static int _Export file_scope_static; //expected-error {{needs to have 
external linkage to be '_Export` qualified}}
+struct S {
+  int _Export nonstaticdatamember; //expected-error {{needs to have external 
linkage to be '_Export` qualified}}
+};
+void g() {
+  int _Export automatic; //expected-error {{needs to have external linkage to 
be '_Export` qualified}}
+}
+
+static void _Export static_func() { //expected-error {{needs to have external 
linkage to be '_Export` qualified}}
+}
+
+void _Export h() {
+  static_func();
+}
+
+void j...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/140944
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to