Author: rsmith Date: Mon Apr 22 15:50:11 2019 New Revision: 358932 URL: http://llvm.org/viewvc/llvm-project?rev=358932&view=rev Log: [c++2a] Implement semantic restrictions for 'export' declarations.
Added: cfe/trunk/test/CXX/module/module.interface/Inputs/ cfe/trunk/test/CXX/module/module.interface/Inputs/header.h cfe/trunk/test/CXX/module/module.interface/p2.cpp cfe/trunk/test/CXX/module/module.interface/p3.cpp cfe/trunk/test/CXX/module/module.interface/p5.cpp Modified: cfe/trunk/include/clang/AST/Decl.h cfe/trunk/include/clang/AST/DeclBase.h cfe/trunk/include/clang/Basic/DiagnosticGroups.td cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/AST/DeclBase.cpp cfe/trunk/lib/Parse/ParseDeclCXX.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/lib/Sema/SemaModule.cpp cfe/trunk/test/CXX/module/module.interface/p1.cpp cfe/trunk/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp cfe/trunk/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm cfe/trunk/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp cfe/trunk/test/SemaCXX/anonymous-union-export.cpp cfe/trunk/test/SemaCXX/modules-ts.cppm Modified: cfe/trunk/include/clang/AST/Decl.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=358932&r1=358931&r2=358932&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Decl.h (original) +++ cfe/trunk/include/clang/AST/Decl.h Mon Apr 22 15:50:11 2019 @@ -4239,8 +4239,10 @@ public: SourceLocation getRBraceLoc() const { return RBraceLoc; } void setRBraceLoc(SourceLocation L) { RBraceLoc = L; } + bool hasBraces() const { return RBraceLoc.isValid(); } + SourceLocation getEndLoc() const LLVM_READONLY { - if (RBraceLoc.isValid()) + if (hasBraces()) return RBraceLoc; // No braces: get the end location of the (only) declaration in context // (if present). Modified: cfe/trunk/include/clang/AST/DeclBase.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=358932&r1=358931&r2=358932&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclBase.h (original) +++ cfe/trunk/include/clang/AST/DeclBase.h Mon Apr 22 15:50:11 2019 @@ -600,10 +600,6 @@ public: return getModuleOwnershipKind() == ModuleOwnershipKind::ModulePrivate; } - /// Whether this declaration is exported (by virtue of being lexically - /// within an ExportDecl or by being a NamespaceDecl). - bool isExported() const; - /// Return true if this declaration has an attribute which acts as /// definition of the entity, such as 'alias' or 'ifunc'. bool hasDefiningAttr() const; Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=358932&r1=358931&r2=358932&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Mon Apr 22 15:50:11 2019 @@ -168,6 +168,7 @@ def ExtraTokens : DiagGroup<"extra-token def CXX98CompatExtraSemi : DiagGroup<"c++98-compat-extra-semi">; def CXX11ExtraSemi : DiagGroup<"c++11-extra-semi">; def EmptyInitStatement : DiagGroup<"empty-init-stmt">; +def ExportUnnamed : DiagGroup<"export-unnamed">; def ExtraSemiStmt : DiagGroup<"extra-semi-stmt", [EmptyInitStatement]>; def ExtraSemi : DiagGroup<"extra-semi", [CXX98CompatExtraSemi, CXX11ExtraSemi]>; Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=358932&r1=358931&r2=358932&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Apr 22 15:50:11 2019 @@ -9273,8 +9273,27 @@ def err_module_decl_not_at_start : Error def note_global_module_introducer_missing : Note< "add 'module;' to the start of the file to introduce a " "global module fragment">; +def err_export_within_anonymous_namespace : Error< + "export declaration appears within anonymous namespace">; +def note_anonymous_namespace : Note<"anonymous namespace begins here">; +def ext_export_no_name_block : ExtWarn< + "ISO C++20 does not permit %select{an empty|a static_assert}0 declaration " + "to appear in an export block">, InGroup<ExportUnnamed>; +def ext_export_no_names : ExtWarn< + "ISO C++20 does not permit a declaration that does not introduce any names " + "to be exported">, InGroup<ExportUnnamed>; +def note_export : Note<"export block begins here">; +def err_export_no_name : Error< + "%select{empty|static_assert|asm}0 declaration cannot be exported">; +def ext_export_using_directive : ExtWarn< + "ISO C++20 does not permit using directive to be exported">, + InGroup<DiagGroup<"export-using-directive">>; def err_export_within_export : Error< "export declaration appears within another export declaration">; +def err_export_internal : Error< + "declaration of %0 with internal linkage cannot be exported">; +def err_export_using_internal : Error< + "using declaration referring to %0 with internal linkage cannot be exported">; def err_export_not_in_module_interface : Error< "export declaration can only be used within a module interface unit" "%select{ after the module declaration|}0">; Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=358932&r1=358931&r2=358932&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Mon Apr 22 15:50:11 2019 @@ -1651,6 +1651,9 @@ private: /// The modules we're currently parsing. llvm::SmallVector<ModuleScope, 16> ModuleScopes; + /// Namespace definitions that we will export when they finish. + llvm::SmallPtrSet<const NamespaceDecl*, 8> DeferredExportedNamespaces; + /// Get the module whose scope we are currently within. Module *getCurrentModule() const { return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module; Modified: cfe/trunk/lib/AST/DeclBase.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=358932&r1=358931&r2=358932&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclBase.cpp (original) +++ cfe/trunk/lib/AST/DeclBase.cpp Mon Apr 22 15:50:11 2019 @@ -430,22 +430,6 @@ bool Decl::isReferenced() const { return false; } -bool Decl::isExported() const { - if (isModulePrivate()) - return false; - // Namespaces are always exported. - if (isa<TranslationUnitDecl>(this) || isa<NamespaceDecl>(this)) - return true; - // Otherwise, this is a strictly lexical check. - for (auto *DC = getLexicalDeclContext(); DC; DC = DC->getLexicalParent()) { - if (cast<Decl>(DC)->isModulePrivate()) - return false; - if (isa<ExportDecl>(DC)) - return true; - } - return false; -} - ExternalSourceSymbolAttr *Decl::getExternalSourceSymbolAttr() const { const Decl *Definition = nullptr; if (auto *ID = dyn_cast<ObjCInterfaceDecl>(this)) { Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=358932&r1=358931&r2=358932&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Apr 22 15:50:11 2019 @@ -437,9 +437,10 @@ Decl *Parser::ParseExportDeclaration() { // The Modules TS draft says "An export-declaration shall declare at least one // entity", but the intent is that it shall contain at least one declaration. - if (Tok.is(tok::r_brace)) + if (Tok.is(tok::r_brace) && getLangOpts().ModulesTS) { Diag(ExportLoc, diag::err_export_empty) << SourceRange(ExportLoc, Tok.getLocation()); + } while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=358932&r1=358931&r2=358932&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Apr 22 15:50:11 2019 @@ -9037,6 +9037,9 @@ void Sema::ActOnFinishNamespaceDef(Decl PopDeclContext(); if (Namespc->hasAttr<VisibilityAttr>()) PopPragmaVisibility(true, RBrace); + // If this namespace contains an export-declaration, export it now. + if (DeferredExportedNamespaces.erase(Namespc)) + Dcl->setModuleOwnershipKind(Decl::ModuleOwnershipKind::VisibleWhenImported); } CXXRecordDecl *Sema::getStdBadAlloc() const { Modified: cfe/trunk/lib/Sema/SemaModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaModule.cpp?rev=358932&r1=358931&r2=358932&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaModule.cpp (original) +++ cfe/trunk/lib/Sema/SemaModule.cpp Mon Apr 22 15:50:11 2019 @@ -330,6 +330,14 @@ DeclResult Sema::ActOnModuleImport(Sourc return ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Mod, Path); } +/// Determine whether \p D is lexically within an export-declaration. +static const ExportDecl *getEnclosingExportDecl(const Decl *D) { + for (auto *DC = D->getLexicalDeclContext(); DC; DC = DC->getLexicalParent()) + if (auto *ED = dyn_cast<ExportDecl>(DC)) + return ED; + return nullptr; +} + DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, SourceLocation ExportLoc, SourceLocation ImportLoc, @@ -384,7 +392,7 @@ DeclResult Sema::ActOnModuleImport(Sourc // Re-export the module if needed. if (!ModuleScopes.empty() && ModuleScopes.back().ModuleInterface) { - if (ExportLoc.isValid() || Import->isExported()) + if (ExportLoc.isValid() || getEnclosingExportDecl(Import)) getCurrentModule()->Exports.emplace_back(Mod, false); } else if (ExportLoc.isValid()) { Diag(ExportLoc, diag::err_export_not_in_module_interface); @@ -516,11 +524,13 @@ Decl *Sema::ActOnStartExportDecl(Scope * SourceLocation LBraceLoc) { ExportDecl *D = ExportDecl::Create(Context, CurContext, ExportLoc); - // C++20 [module.interface]p1: + // Set this temporarily so we know the export-declaration was braced. + D->setRBraceLoc(LBraceLoc); + + // C++2a [module.interface]p1: // An export-declaration shall appear only [...] in the purview of a module // interface unit. An export-declaration shall not appear directly or - // indirectly within an unnamed namespace or a private-module-fragment. - // FIXME: Check for the unnamed namespace case. + // indirectly within [...] a private-module-fragment. if (ModuleScopes.empty() || !ModuleScopes.back().Module->isModulePurview()) { Diag(ExportLoc, diag::err_export_not_in_module_interface) << 0; } else if (!ModuleScopes.back().ModuleInterface) { @@ -534,10 +544,35 @@ Decl *Sema::ActOnStartExportDecl(Scope * Diag(ModuleScopes.back().BeginLoc, diag::note_private_module_fragment); } + for (const DeclContext *DC = CurContext; DC; DC = DC->getLexicalParent()) { + if (const auto *ND = dyn_cast<NamespaceDecl>(DC)) { + // An export-declaration shall not appear directly or indirectly within + // an unnamed namespace [...] + if (ND->isAnonymousNamespace()) { + Diag(ExportLoc, diag::err_export_within_anonymous_namespace); + Diag(ND->getLocation(), diag::note_anonymous_namespace); + // Don't diagnose internal-linkage declarations in this region. + D->setInvalidDecl(); + break; + } + + // A declaration is exported if it is [...] a namespace-definition + // that contains an exported declaration. + // + // Defer exporting the namespace until after we leave it, in order to + // avoid marking all subsequent declarations in the namespace as exported. + if (!DeferredExportedNamespaces.insert(ND).second) + break; + } + } + // [...] its declaration or declaration-seq shall not contain an // export-declaration. - if (D->isExported()) + if (auto *ED = getEnclosingExportDecl(D)) { Diag(ExportLoc, diag::err_export_within_export); + if (ED->hasBraces()) + Diag(ED->getLocation(), diag::note_export); + } CurContext->addDecl(D); PushDeclContext(S, D); @@ -545,15 +580,131 @@ Decl *Sema::ActOnStartExportDecl(Scope * return D; } +static bool checkExportedDeclContext(Sema &S, DeclContext *DC, + SourceLocation BlockStart); + +namespace { +enum class UnnamedDeclKind { + Empty, + StaticAssert, + Asm, + UsingDirective, + Context +}; +} + +static llvm::Optional<UnnamedDeclKind> getUnnamedDeclKind(Decl *D) { + if (isa<EmptyDecl>(D)) + return UnnamedDeclKind::Empty; + if (isa<StaticAssertDecl>(D)) + return UnnamedDeclKind::StaticAssert; + if (isa<FileScopeAsmDecl>(D)) + return UnnamedDeclKind::Asm; + if (isa<UsingDirectiveDecl>(D)) + return UnnamedDeclKind::UsingDirective; + // Everything else either introduces one or more names or is ill-formed. + return llvm::None; +} + +unsigned getUnnamedDeclDiag(UnnamedDeclKind UDK, bool InBlock) { + switch (UDK) { + case UnnamedDeclKind::Empty: + case UnnamedDeclKind::StaticAssert: + // Allow empty-declarations and static_asserts in an export block as an + // extension. + return InBlock ? diag::ext_export_no_name_block : diag::err_export_no_name; + + case UnnamedDeclKind::UsingDirective: + // Allow exporting using-directives as an extension. + return diag::ext_export_using_directive; + + case UnnamedDeclKind::Context: + // Allow exporting DeclContexts that transitively contain no declarations + // as an extension. + return diag::ext_export_no_names; + + case UnnamedDeclKind::Asm: + return diag::err_export_no_name; + } + llvm_unreachable("unknown kind"); +} + +static void diagExportedUnnamedDecl(Sema &S, UnnamedDeclKind UDK, Decl *D, + SourceLocation BlockStart) { + S.Diag(D->getLocation(), getUnnamedDeclDiag(UDK, BlockStart.isValid())) + << (unsigned)UDK; + if (BlockStart.isValid()) + S.Diag(BlockStart, diag::note_export); +} + +/// Check that it's valid to export \p D. +static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) { + // C++2a [module.interface]p3: + // An exported declaration shall declare at least one name + if (auto UDK = getUnnamedDeclKind(D)) + diagExportedUnnamedDecl(S, *UDK, D, BlockStart); + + // [...] shall not declare a name with internal linkage. + if (auto *ND = dyn_cast<NamedDecl>(D)) { + // Don't diagnose anonymous union objects; we'll diagnose their members + // instead. + if (ND->getDeclName() && ND->getFormalLinkage() == InternalLinkage) { + S.Diag(ND->getLocation(), diag::err_export_internal) << ND; + if (BlockStart.isValid()) + S.Diag(BlockStart, diag::note_export); + } + } + + // C++2a [module.interface]p5: + // all entities to which all of the using-declarators ultimately refer + // shall have been introduced with a name having external linkage + if (auto *USD = dyn_cast<UsingShadowDecl>(D)) { + NamedDecl *Target = USD->getUnderlyingDecl(); + if (Target->getFormalLinkage() == InternalLinkage) { + S.Diag(USD->getLocation(), diag::err_export_using_internal) << Target; + S.Diag(Target->getLocation(), diag::note_using_decl_target); + if (BlockStart.isValid()) + S.Diag(BlockStart, diag::note_export); + } + } + + // Recurse into namespace-scope DeclContexts. (Only namespace-scope + // declarations are exported.) + if (auto *DC = dyn_cast<DeclContext>(D)) + if (DC->getRedeclContext()->isFileContext() && !isa<EnumDecl>(D)) + return checkExportedDeclContext(S, DC, BlockStart); + return false; +} + +/// Check that it's valid to export all the declarations in \p DC. +static bool checkExportedDeclContext(Sema &S, DeclContext *DC, + SourceLocation BlockStart) { + bool AllUnnamed = true; + for (auto *D : DC->decls()) + AllUnnamed &= checkExportedDecl(S, D, BlockStart); + return AllUnnamed; +} + /// Complete the definition of an export declaration. Decl *Sema::ActOnFinishExportDecl(Scope *S, Decl *D, SourceLocation RBraceLoc) { auto *ED = cast<ExportDecl>(D); if (RBraceLoc.isValid()) ED->setRBraceLoc(RBraceLoc); - // FIXME: Diagnose export of internal-linkage declaration (including - // anonymous namespace). - PopDeclContext(); + + if (!D->isInvalidDecl()) { + SourceLocation BlockStart = + ED->hasBraces() ? ED->getBeginLoc() : SourceLocation(); + for (auto *Child : ED->decls()) { + if (checkExportedDecl(*this, Child, BlockStart)) { + // If a top-level child is a linkage-spec declaration, it might contain + // no declarations (transitively), in which case it's ill-formed. + diagExportedUnnamedDecl(*this, UnnamedDeclKind::Context, Child, + BlockStart); + } + } + } + return D; } Added: cfe/trunk/test/CXX/module/module.interface/Inputs/header.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/module/module.interface/Inputs/header.h?rev=358932&view=auto ============================================================================== --- cfe/trunk/test/CXX/module/module.interface/Inputs/header.h (added) +++ cfe/trunk/test/CXX/module/module.interface/Inputs/header.h Mon Apr 22 15:50:11 2019 @@ -0,0 +1,3 @@ +extern int foo; +namespace bar { extern int baz(); } +static int baz; Modified: cfe/trunk/test/CXX/module/module.interface/p1.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/module/module.interface/p1.cpp?rev=358932&r1=358931&r2=358932&view=diff ============================================================================== --- cfe/trunk/test/CXX/module/module.interface/p1.cpp (original) +++ cfe/trunk/test/CXX/module/module.interface/p1.cpp Mon Apr 22 15:50:11 2019 @@ -23,15 +23,15 @@ namespace N { } #ifdef ERRORS -namespace { - export int d1; // FIXME: invalid +namespace { // expected-note 2{{anonymous namespace begins here}} + export int d1; // expected-error {{export declaration appears within anonymous namespace}} namespace X { - export int d2; // FIXME: invalid + export int d2; // expected-error {{export declaration appears within anonymous namespace}} } } export export int e; // expected-error {{within another export declaration}} -export { export int f; } // expected-error {{within another export declaration}} +export { export int f; } // expected-error {{within another export declaration}} expected-note {{export block begins here}} module :private; // expected-note {{private module fragment begins here}} export int priv; // expected-error {{export declaration cannot be used in a private module fragment}} Added: cfe/trunk/test/CXX/module/module.interface/p2.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/module/module.interface/p2.cpp?rev=358932&view=auto ============================================================================== --- cfe/trunk/test/CXX/module/module.interface/p2.cpp (added) +++ cfe/trunk/test/CXX/module/module.interface/p2.cpp Mon Apr 22 15:50:11 2019 @@ -0,0 +1,94 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: %clang_cc1 -std=c++2a -x c++-header %S/Inputs/header.h -emit-header-module -fmodule-name=FIXME -o %t/h.pcm +// RUN: %clang_cc1 -std=c++2a %s -DX_INTERFACE -emit-module-interface -o %t/x.pcm +// RUN: %clang_cc1 -std=c++2a %s -DY_INTERFACE -emit-module-interface -o %t/y.pcm +// RUN: %clang_cc1 -std=c++2a %s -DINTERFACE -fmodule-file=%t/x.pcm -fmodule-file=%t/y.pcm -emit-module-interface -o %t/m.pcm +// RUN: %clang_cc1 -std=c++2a %s -DIMPLEMENTATION -I%S/Inputs -fmodule-file=%t/h.pcm -fmodule-file=%t/m.pcm -verify +// RUN: %clang_cc1 -std=c++2a %s -DUSER -I%S/Inputs -fmodule-file=%t/h.pcm -fmodule-file=%t/m.pcm -verify + +#if defined(X_INTERFACE) +export module X; +export int x; + +#elif defined(Y_INTERFACE) +export module Y; +export int y; + +#elif defined(INTERFACE) +export module p2; +export import X; +import Y; // not exported + +namespace A { + int f(); + export int g(); + int h(); + namespace inner {} +} +export namespace B { + namespace inner {} +} +namespace B { + int f(); +} +namespace C {} +namespace D { int f(); } +export namespace D {} + +#elif defined(IMPLEMENTATION) +module p2; +import "header.h"; + +// Per [basic.scope.namespace]/2.3, exportedness has no impact on visibility +// within the same module. +// +// expected-no-diagnostics + +void use() { + A::f(); + A::g(); + A::h(); + using namespace A::inner; + + using namespace B; + using namespace B::inner; + B::f(); + f(); + + using namespace C; + + D::f(); +} + +int use_header() { return foo + bar::baz(); } + +#elif defined(USER) +import p2; +import "header.h"; + +void use() { + // namespace A is implicitly exported by the export of A::g. + A::f(); // expected-error {{no member named 'f' in namespace 'A'}} + A::g(); + A::h(); // expected-error {{no member named 'h' in namespace 'A'}} + using namespace A::inner; // expected-error {{expected namespace name}} + + // namespace B and B::inner are explicitly exported + using namespace B; + using namespace B::inner; + B::f(); // expected-error {{no member named 'f' in namespace 'B'}} + f(); // expected-error {{undeclared identifier 'f'}} + + // namespace C is not exported + using namespace C; // expected-error {{expected namespace name}} + + // namespace D is exported, but D::f is not + D::f(); // expected-error {{no member named 'f' in namespace 'D'}} +} + +int use_header() { return foo + bar::baz(); } + +#else +#error unknown mode +#endif Added: cfe/trunk/test/CXX/module/module.interface/p3.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/module/module.interface/p3.cpp?rev=358932&view=auto ============================================================================== --- cfe/trunk/test/CXX/module/module.interface/p3.cpp (added) +++ cfe/trunk/test/CXX/module/module.interface/p3.cpp Mon Apr 22 15:50:11 2019 @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -std=c++2a %s -verify -pedantic-errors + +export module p3; + +namespace A { int ns_mem; } + +// An exported declaration shall declare at least one name. +export; // expected-error {{empty declaration cannot be exported}} +export static_assert(true); // expected-error {{static_assert declaration cannot be exported}} +export using namespace A; // expected-error {{ISO C++20 does not permit using directive to be exported}} + +export { // expected-note 3{{export block begins here}} + ; // expected-error {{ISO C++20 does not permit an empty declaration to appear in an export block}} + static_assert(true); // expected-error {{ISO C++20 does not permit a static_assert declaration to appear in an export block}} + using namespace A; // expected-error {{ISO C++20 does not permit using directive to be exported}} +} + +export struct {}; // expected-error {{must be class member}} expected-error {{GNU extension}} +export struct {} struct_; +export union {}; // expected-error {{must be declared 'static'}} +export union {} union_; +export enum {}; // expected-error {{does not declare anything}} +export enum {} enum_; +export enum E : int; +export typedef int; // expected-error {{typedef requires a name}} +export static union {}; // FIXME: this declaration is ill-formed even without the 'export' +export asm(""); // expected-error {{asm declaration cannot be exported}} +export namespace B = A; +export using A::ns_mem; +namespace A { + export using A::ns_mem; +} +export using Int = int; +export extern "C++" {} // expected-error {{ISO C++20 does not permit a declaration that does not introduce any names to be exported}} +export extern "C++" { extern "C" {} } // expected-error {{ISO C++20 does not permit a declaration that does not introduce any names to be exported}} +export extern "C++" { extern "C" int extern_c; } +export { // expected-note {{export block}} + extern "C++" int extern_cxx; + extern "C++" {} // expected-error {{ISO C++20 does not permit a declaration that does not introduce any names to be exported}} +} +export [[]]; // FIXME (bad diagnostic text): expected-error {{empty declaration cannot be exported}} +export [[example::attr]]; // FIXME: expected-error {{empty declaration cannot be exported}} expected-warning {{unknown attribute 'attr'}} + +// [...] shall not declare a name with internal linkage +export static int a; // expected-error {{declaration of 'a' with internal linkage cannot be exported}} +export static int b(); // expected-error {{declaration of 'b' with internal linkage cannot be exported}} +export namespace { int c; } // expected-error {{declaration of 'c' with internal linkage cannot be exported}} +namespace { // expected-note {{here}} + export int d; // expected-error {{export declaration appears within anonymous namespace}} +} +export template<typename> static int e; // FIXME +export template<typename> static int f(); // expected-error {{declaration of 'f' with internal linkage cannot be exported}} +export const int k = 5; +export static union { int n; }; // expected-error {{declaration of 'n' with internal linkage cannot be exported}} Added: cfe/trunk/test/CXX/module/module.interface/p5.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/module/module.interface/p5.cpp?rev=358932&view=auto ============================================================================== --- cfe/trunk/test/CXX/module/module.interface/p5.cpp (added) +++ cfe/trunk/test/CXX/module/module.interface/p5.cpp Mon Apr 22 15:50:11 2019 @@ -0,0 +1,89 @@ +// RUN: %clang_cc1 -std=c++2a %s -verify -pedantic-errors + +export module p5; + +int a; +static int sa; // expected-note {{target}} +void b(); +static void sb(); // expected-note {{target}} +struct c {}; +enum d {}; +using e = int; +using f = c; +static union { int sg1, sg2; }; // expected-note {{target}} +namespace NS {} + +template<typename> int ta; +template<typename> static int sta; +template<typename> void tb(); +template<typename> static void stb(); // expected-note {{target}} +template<typename> struct tc {}; +template<typename> using te = int; +template<typename> using tf = c; + +namespace UnnamedNS { + namespace { + int a; // expected-note {{target}} + static int sa; // expected-note {{target}} + void b(); // expected-note {{target}} + static void sb(); // expected-note {{target}} + struct c {}; // expected-note {{target}} + enum d {}; // expected-note {{target}} + using e = int; + using f = c; + static union { int sg1, sg2; }; // expected-note {{target}} + namespace NS {} + + template<typename> int ta; // expected-note {{target}} + template<typename> static int sta; // expected-note {{target}} + template<typename> void tb(); // expected-note {{target}} + template<typename> static void stb(); // expected-note {{target}} + template<typename> struct tc {}; // expected-note {{target}} + template<typename> using te = int; // expected-note {{target}} + template<typename> using tf = c; // expected-note {{target}} + } +} + +export { // expected-note 18{{here}} + using ::a; + using ::sa; // expected-error {{using declaration referring to 'sa' with internal linkage}} + using ::b; + using ::sb; // expected-error {{using declaration referring to 'sb' with internal linkage}} + using ::c; + using ::d; + using ::e; + using ::f; + using ::sg1; // expected-error {{using declaration referring to 'sg1' with internal linkage}} + + using ::ta; + using ::sta; // FIXME {{using declaration referring to 'sta' with internal linkage}} + using ::tb; + using ::stb; // expected-error {{using declaration referring to 'stb' with internal linkage}} + using ::tc; + using ::te; + using ::tf; + namespace NS2 = ::NS; + + namespace UnnamedNS { + using UnnamedNS::a; // expected-error {{internal linkage}} + using UnnamedNS::sa; // expected-error {{internal linkage}} + using UnnamedNS::b; // expected-error {{internal linkage}} + using UnnamedNS::sb; // expected-error {{internal linkage}} + using UnnamedNS::c; // expected-error {{internal linkage}} + using UnnamedNS::d; // expected-error {{internal linkage}} + using UnnamedNS::e; // ok + using UnnamedNS::f; // ok? using-declaration refers to alias-declaration, + // which does not have linkage (even though that then + // refers to a type that has internal linkage) + using UnnamedNS::sg1; // expected-error {{internal linkage}} + + using UnnamedNS::ta; // expected-error {{internal linkage}} + using UnnamedNS::sta; // expected-error {{internal linkage}} + using UnnamedNS::tb; // expected-error {{internal linkage}} + using UnnamedNS::stb; // expected-error {{internal linkage}} + using UnnamedNS::tc; // expected-error {{internal linkage}} + using UnnamedNS::te; // expected-error {{internal linkage}} + using UnnamedNS::tf; // expected-error {{internal linkage}} + namespace NS2 = UnnamedNS::NS; // ok (wording bug?) + } +} Modified: cfe/trunk/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp?rev=358932&r1=358931&r2=358932&view=diff ============================================================================== --- cfe/trunk/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp (original) +++ cfe/trunk/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp Mon Apr 22 15:50:11 2019 @@ -3,7 +3,6 @@ // CHECK-DAG: @extern_var_exported = external {{(dso_local )?}}global // CHECK-DAG: @inline_var_exported = linkonce_odr {{(dso_local )?}}global -// CHECK-DAG: @_ZW6ModuleE19static_var_exported = available_externally {{(dso_local )?}}global i32 0, // CHECK-DAG: @const_var_exported = available_externally {{(dso_local )?}}constant i32 3, // // CHECK-DAG: @_ZW6ModuleE25extern_var_module_linkage = external {{(dso_local )?}}global @@ -21,7 +20,6 @@ void use() { (void)&extern_var_exported; (void)&inline_var_exported; - (void)&static_var_exported; // FIXME: Should not be exported. (void)&const_var_exported; // FIXME: This symbol should not be visible here. Modified: cfe/trunk/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm?rev=358932&r1=358931&r2=358932&view=diff ============================================================================== --- cfe/trunk/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm (original) +++ cfe/trunk/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm Mon Apr 22 15:50:11 2019 @@ -11,7 +11,6 @@ // can discard this global and its initializer (if any), and other TUs are not // permitted to run the initializer for this variable. // CHECK-DAG: @inline_var_exported = linkonce_odr {{(dso_local )?}}global -// CHECK-DAG: @_ZW6ModuleE19static_var_exported = {{(dso_local )?}}global // CHECK-DAG: @const_var_exported = {{(dso_local )?}}constant // // CHECK-DAG: @_ZW6ModuleE25extern_var_module_linkage = external {{(dso_local )?}}global @@ -58,32 +57,17 @@ void noninline_global_module() { export module Module; export { - // FIXME: These should be ill-formed: you can't export an internal linkage - // symbol, per [dcl.module.interface]p2. - // CHECK: define {{(dso_local )?}}void {{.*}}@_ZW6ModuleE22unused_static_exportedv - static void unused_static_exported() {} - // CHECK: define {{(dso_local )?}}void {{.*}}@_ZW6ModuleE20used_static_exportedv - static void used_static_exported() {} - inline void unused_inline_exported() {} inline void used_inline_exported() {} extern int extern_var_exported; inline int inline_var_exported; - // FIXME: This should be ill-formed: you can't export an internal linkage - // symbol. - static int static_var_exported; const int const_var_exported = 3; // CHECK: define {{(dso_local )?}}void {{.*}}@_Z18noninline_exportedv void noninline_exported() { - used_static_exported(); - // CHECK: define linkonce_odr {{.*}}@_Z20used_inline_exportedv - used_inline_exported(); - (void)&extern_var_exported; (void)&inline_var_exported; - (void)&static_var_exported; (void)&const_var_exported; } } Modified: cfe/trunk/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp?rev=358932&r1=358931&r2=358932&view=diff ============================================================================== --- cfe/trunk/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp (original) +++ cfe/trunk/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp Mon Apr 22 15:50:11 2019 @@ -3,7 +3,6 @@ // CHECK-DAG: @extern_var_exported = external {{(dso_local )?}}global // CHECK-DAG: @inline_var_exported = linkonce_odr {{(dso_local )?}}global -// CHECK-DAG: @_ZW6ModuleE19static_var_exported = available_externally {{(dso_local )?}}global i32 0 // CHECK-DAG: @const_var_exported = available_externally {{(dso_local )?}}constant i32 3 import Module; @@ -16,7 +15,6 @@ void use() { (void)&extern_var_exported; (void)&inline_var_exported; - (void)&static_var_exported; (void)&const_var_exported; // Module-linkage declarations are not visible here. Modified: cfe/trunk/test/SemaCXX/anonymous-union-export.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/anonymous-union-export.cpp?rev=358932&r1=358931&r2=358932&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/anonymous-union-export.cpp (original) +++ cfe/trunk/test/SemaCXX/anonymous-union-export.cpp Mon Apr 22 15:50:11 2019 @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -std=c++17 -fmodules-ts -emit-obj -verify -o %t.pcm %s export module M; -export { - union { bool a; }; // expected-error{{anonymous unions at namespace or global scope must be declared 'static'}} +export { // expected-note 2{{export block begins here}} + union { bool a; }; // expected-error {{anonymous unions at namespace or global scope must be declared 'static'}} expected-error {{declaration of 'a' with internal linkage cannot be exported}} + static union { bool a; }; // expected-error {{declaration of 'a' with internal linkage cannot be exported}} } Modified: cfe/trunk/test/SemaCXX/modules-ts.cppm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/modules-ts.cppm?rev=358932&r1=358931&r2=358932&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/modules-ts.cppm (original) +++ cfe/trunk/test/SemaCXX/modules-ts.cppm Mon Apr 22 15:50:11 2019 @@ -49,8 +49,12 @@ int use_a = a; // expected-error {{decla import foo; export {} // expected-error {{export declaration cannot be empty}} -export { ; } -export { static_assert(true); } +export { // expected-note {{begins here}} + ; // expected-warning {{ISO C++20 does not permit an empty declaration to appear in an export block}} +} +export { // expected-note {{begins here}} + static_assert(true); // expected-warning {{ISO C++20 does not permit a static_assert declaration to appear in an export block}} +} int use_b = b; int use_n = n; // FIXME: this should not be visible, because it is not exported @@ -74,7 +78,7 @@ struct S { // language rules right now, but (per personal correspondence between zygoloid // and gdr) is the intent. #if TEST == 1 -export { +export { // expected-note {{export block begins here}} extern "C++" { namespace NestedExport { export { // expected-error {{appears within another export}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits