r358932 - [c++2a] Implement semantic restrictions for 'export' declarations.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 22 15:50:11 PDT 2019
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}}
More information about the cfe-commits
mailing list