summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/AST/DeclBase.h4
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--clang/lib/AST/DeclBase.cpp16
-rw-r--r--clang/lib/Sema/SemaDecl.cpp7
-rw-r--r--clang/test/SemaCXX/modules-ts.cppm15
5 files changed, 42 insertions, 2 deletions
diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index 970ba8a7a21..3a80ff5b234 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -568,6 +568,10 @@ public:
return NextInContextAndBits.getInt() & ModulePrivateFlag;
}
+ /// \brief 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;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index cbedb5b8c00..af484d40038 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8522,6 +8522,8 @@ def err_module_self_import : Error<
"import of module '%0' appears within same top-level module '%1'">;
def err_module_import_in_implementation : Error<
"@import of module '%0' in implementation of '%1'; use #import">;
+def err_export_within_export : Error<
+ "export declaration appears within another export declaration">;
def ext_equivalent_internal_linkage_decl_in_modules : ExtWarn<
"ambiguous use of internal linkage declaration %0 defined in multiple modules">,
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index cea511b5118..77e74b044fd 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -377,6 +377,22 @@ 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;
+}
+
bool Decl::hasDefiningAttr() const {
return hasAttr<AliasAttr>() || hasAttr<IFuncAttr>();
}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 3eb00625a45..cfb1f99b07c 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15465,14 +15465,17 @@ void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc,
/// (if present).
Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
SourceLocation LBraceLoc) {
- // FIXME: C++ Modules TS:
+ ExportDecl *D = ExportDecl::Create(Context, CurContext, ExportLoc);
+
+ // C++ Modules TS draft:
// An export-declaration [...] shall not contain more than one
// export keyword.
//
// The intent here is that an export-declaration cannot appear within another
// export-declaration.
+ if (D->isExported())
+ Diag(ExportLoc, diag::err_export_within_export);
- ExportDecl *D = ExportDecl::Create(Context, CurContext, ExportLoc);
CurContext->addDecl(D);
PushDeclContext(S, D);
return D;
diff --git a/clang/test/SemaCXX/modules-ts.cppm b/clang/test/SemaCXX/modules-ts.cppm
index 61e9e43cad0..71c09d3bfe6 100644
--- a/clang/test/SemaCXX/modules-ts.cppm
+++ b/clang/test/SemaCXX/modules-ts.cppm
@@ -66,3 +66,18 @@ struct S {
// FIXME: Exports of declarations without external linkage are disallowed.
// Exports of declarations with non-external-linkage types are disallowed.
+
+// Cannot export within another export. This isn't precisely covered by the
+// language rules right now, but (per personal correspondence between zygoloid
+// and gdr) is the intent.
+#if TEST == 1
+export {
+ extern "C++" {
+ namespace NestedExport {
+ export { // expected-error {{appears within another export}}
+ int q;
+ }
+ }
+ }
+}
+#endif
OpenPOWER on IntegriCloud