C++ Modules TS: Add parsing and some semantic analysis support for

export-declarations. These don't yet have an effect on name visibility;
we still export everything by default.

llvm-svn: 280999
This commit is contained in:
Richard Smith 2016-09-08 23:14:54 +00:00
parent 10037b93e9
commit 8df390f9eb
26 changed files with 329 additions and 45 deletions

View File

@ -3792,6 +3792,55 @@ public:
static bool classofKind(Kind K) { return K == Import; }
};
/// \brief Represents a C++ Modules TS module export declaration.
///
/// For example:
/// \code
/// export void foo();
/// \endcode
class ExportDecl final : public Decl, public DeclContext {
virtual void anchor();
private:
/// \brief The source location for the right brace (if valid).
SourceLocation RBraceLoc;
ExportDecl(DeclContext *DC, SourceLocation ExportLoc)
: Decl(Export, DC, ExportLoc), DeclContext(Export),
RBraceLoc(SourceLocation()) { }
friend class ASTDeclReader;
public:
static ExportDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation ExportLoc);
static ExportDecl *CreateDeserialized(ASTContext &C, unsigned ID);
SourceLocation getExportLoc() const { return getLocation(); }
SourceLocation getRBraceLoc() const { return RBraceLoc; }
void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
SourceLocation getLocEnd() const LLVM_READONLY {
if (RBraceLoc.isValid())
return RBraceLoc;
// No braces: get the end location of the (only) declaration in context
// (if present).
return decls_empty() ? getLocation() : decls_begin()->getLocEnd();
}
SourceRange getSourceRange() const override LLVM_READONLY {
return SourceRange(getLocation(), getLocEnd());
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == Export; }
static DeclContext *castToDeclContext(const ExportDecl *D) {
return static_cast<DeclContext *>(const_cast<ExportDecl*>(D));
}
static ExportDecl *castFromDeclContext(const DeclContext *DC) {
return static_cast<ExportDecl *>(const_cast<DeclContext*>(DC));
}
};
/// \brief Represents an empty-declaration.
class EmptyDecl : public Decl {
virtual void anchor();

View File

@ -33,6 +33,7 @@ class DeclContext;
class DeclarationName;
class DependentDiagnostic;
class EnumDecl;
class ExportDecl;
class FunctionDecl;
class FunctionType;
enum Linkage : unsigned char;
@ -1135,6 +1136,7 @@ public:
/// ObjCMethodDecl
/// ObjCContainerDecl
/// LinkageSpecDecl
/// ExportDecl
/// BlockDecl
/// OMPDeclareReductionDecl
///
@ -1279,7 +1281,8 @@ public:
/// \brief Test whether the context supports looking up names.
bool isLookupContext() const {
return !isFunctionOrMethod() && DeclKind != Decl::LinkageSpec;
return !isFunctionOrMethod() && DeclKind != Decl::LinkageSpec &&
DeclKind != Decl::Export;
}
bool isFileContext() const {

View File

@ -1388,6 +1388,8 @@ DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, {
DEF_TRAVERSE_DECL(LinkageSpecDecl, {})
DEF_TRAVERSE_DECL(ExportDecl, {})
DEF_TRAVERSE_DECL(ObjCPropertyImplDecl, {// FIXME: implement this
})

View File

@ -80,6 +80,7 @@ def Named : Decl<1>;
def ObjCProperty : DDecl<Named>;
def ObjCCompatibleAlias : DDecl<Named>;
def LinkageSpec : Decl, DeclContext;
def Export : Decl, DeclContext;
def ObjCPropertyImpl : Decl;
def FileScopeAsm : Decl;
def AccessSpec : Decl;

View File

@ -1040,6 +1040,8 @@ def err_attribute_not_import_attr : Error<
def err_module_expected_semi : Error<
"expected ';' after module name">;
def err_missing_before_module_end : Error<"expected %0 at end of module">;
def err_export_empty : Error<"export declaration cannot be empty">;
}
let CategoryName = "Generics Issue" in {

View File

@ -2412,6 +2412,7 @@ private:
ParsedAttributes& attrs,
BalancedDelimiterTracker &Tracker);
Decl *ParseLinkage(ParsingDeclSpec &DS, unsigned Context);
Decl *ParseExportDeclaration();
Decl *ParseUsingDirectiveOrDeclaration(unsigned Context,
const ParsedTemplateInfo &TemplateInfo,
SourceLocation &DeclEnd,

View File

@ -1922,6 +1922,11 @@ public:
SourceLocation DeclLoc, ArrayRef<Module *> Modules,
MissingImportKind MIK, bool Recover);
Decl *ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
SourceLocation LBraceLoc);
Decl *ActOnFinishExportDecl(Scope *S, Decl *ExportDecl,
SourceLocation RBraceLoc);
/// \brief We've found a use of a templated declaration that would trigger an
/// implicit instantiation. Check that any relevant explicit specializations
/// and partial specializations are visible, and diagnose if not.

View File

@ -410,6 +410,7 @@ namespace clang {
#define OBJCCONTAINER(DERIVED, BASE)
#define FILESCOPEASM(DERIVED, BASE)
#define IMPORT(DERIVED, BASE)
#define EXPORT(DERIVED, BASE)
#define LINKAGESPEC(DERIVED, BASE)
#define OBJCCOMPATIBLEALIAS(DERIVED, BASE)
#define OBJCMETHOD(DERIVED, BASE)

View File

@ -1103,6 +1103,8 @@ namespace clang {
DECL_UNRESOLVED_USING_TYPENAME,
/// \brief A LinkageSpecDecl record.
DECL_LINKAGE_SPEC,
/// \brief An ExportDecl record.
DECL_EXPORT,
/// \brief A CXXRecordDecl record.
DECL_CXX_RECORD,
/// \brief A CXXMethodDecl record.

View File

@ -4310,3 +4310,18 @@ SourceRange ImportDecl::getSourceRange() const {
return SourceRange(getLocation(), getIdentifierLocs().back());
}
//===----------------------------------------------------------------------===//
// ExportDecl Implementation
//===----------------------------------------------------------------------===//
void ExportDecl::anchor() {}
ExportDecl *ExportDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation ExportLoc) {
return new (C, DC) ExportDecl(DC, ExportLoc);
}
ExportDecl *ExportDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) ExportDecl(nullptr, SourceLocation());
}

View File

@ -672,6 +672,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case FriendTemplate:
case AccessSpec:
case LinkageSpec:
case Export:
case FileScopeAsm:
case StaticAssert:
case ObjCPropertyImpl:
@ -957,7 +958,7 @@ bool DeclContext::isDependentContext() const {
bool DeclContext::isTransparentContext() const {
if (DeclKind == Decl::Enum)
return !cast<EnumDecl>(this)->isScoped();
else if (DeclKind == Decl::LinkageSpec)
else if (DeclKind == Decl::LinkageSpec || DeclKind == Decl::Export)
return true;
return false;
@ -996,6 +997,7 @@ DeclContext *DeclContext::getPrimaryContext() {
case Decl::TranslationUnit:
case Decl::ExternCContext:
case Decl::LinkageSpec:
case Decl::Export:
case Decl::Block:
case Decl::Captured:
case Decl::OMPDeclareReduction:
@ -1408,8 +1410,8 @@ NamedDecl *const DeclContextLookupResult::SingleElementDummyList = nullptr;
DeclContext::lookup_result
DeclContext::lookup(DeclarationName Name) const {
assert(DeclKind != Decl::LinkageSpec &&
"Should not perform lookups into linkage specs!");
assert(DeclKind != Decl::LinkageSpec && DeclKind != Decl::Export &&
"should not perform lookups into transparent contexts");
// If we have an external source, ensure that any later redeclarations of this
// context have been loaded, since they may add names to the result of this
@ -1472,8 +1474,8 @@ DeclContext::lookup(DeclarationName Name) const {
DeclContext::lookup_result
DeclContext::noload_lookup(DeclarationName Name) {
assert(DeclKind != Decl::LinkageSpec &&
"Should not perform lookups into linkage specs!");
assert(DeclKind != Decl::LinkageSpec && DeclKind != Decl::Export &&
"should not perform lookups into transparent contexts");
DeclContext *PrimaryContext = getPrimaryContext();
if (PrimaryContext != this)

View File

@ -78,6 +78,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::PragmaDetectMismatch:
case Decl::AccessSpec:
case Decl::LinkageSpec:
case Decl::Export:
case Decl::ObjCPropertyImpl:
case Decl::FileScopeAsm:
case Decl::Friend:

View File

@ -3754,17 +3754,6 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
D->setHasNonZeroConstructors(true);
}
/// EmitNamespace - Emit all declarations in a namespace.
void CodeGenModule::EmitNamespace(const NamespaceDecl *ND) {
for (auto *I : ND->decls()) {
if (const auto *VD = dyn_cast<VarDecl>(I))
if (VD->getTemplateSpecializationKind() != TSK_ExplicitSpecialization &&
VD->getTemplateSpecializationKind() != TSK_Undeclared)
continue;
EmitTopLevelDecl(I);
}
}
// EmitLinkageSpec - Emit all declarations in a linkage spec.
void CodeGenModule::EmitLinkageSpec(const LinkageSpecDecl *LSD) {
if (LSD->getLanguage() != LinkageSpecDecl::lang_c &&
@ -3773,13 +3762,21 @@ void CodeGenModule::EmitLinkageSpec(const LinkageSpecDecl *LSD) {
return;
}
for (auto *I : LSD->decls()) {
// Meta-data for ObjC class includes references to implemented methods.
// Generate class's method definitions first.
EmitDeclContext(LSD);
}
void CodeGenModule::EmitDeclContext(const DeclContext *DC) {
for (auto *I : DC->decls()) {
// Unlike other DeclContexts, the contents of an ObjCImplDecl at TU scope
// are themselves considered "top-level", so EmitTopLevelDecl on an
// ObjCImplDecl does not recursively visit them. We need to do that in
// case they're nested inside another construct (LinkageSpecDecl /
// ExportDecl) that does stop them from being considered "top-level".
if (auto *OID = dyn_cast<ObjCImplDecl>(I)) {
for (auto *M : OID->methods())
EmitTopLevelDecl(M);
}
EmitTopLevelDecl(I);
}
}
@ -3825,7 +3822,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
// C++ Decls
case Decl::Namespace:
EmitNamespace(cast<NamespaceDecl>(D));
EmitDeclContext(cast<NamespaceDecl>(D));
break;
case Decl::CXXRecord:
// Emit any static data members, they may be definitions.
@ -3976,6 +3973,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break;
}
case Decl::Export:
EmitDeclContext(cast<ExportDecl>(D));
break;
case Decl::OMPThreadPrivate:
EmitOMPThreadPrivateDecl(cast<OMPThreadPrivateDecl>(D));
break;

View File

@ -1182,7 +1182,7 @@ private:
// C++ related functions.
void EmitNamespace(const NamespaceDecl *D);
void EmitDeclContext(const DeclContext *DC);
void EmitLinkageSpec(const LinkageSpecDecl *D);
void CompleteDIClassType(const CXXMethodDecl* D);

View File

@ -372,6 +372,53 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
: nullptr;
}
/// Parse a C++ Modules TS export-declaration.
///
/// export-declaration:
/// 'export' declaration
/// 'export' '{' declaration-seq[opt] '}'
///
Decl *Parser::ParseExportDeclaration() {
assert(Tok.is(tok::kw_export));
SourceLocation ExportLoc = ConsumeToken();
ParseScope ExportScope(this, Scope::DeclScope);
Decl *ExportDecl = Actions.ActOnStartExportDecl(
getCurScope(), ExportLoc,
Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation());
if (Tok.isNot(tok::l_brace)) {
// FIXME: Factor out a ParseExternalDeclarationWithAttrs.
ParsedAttributesWithRange Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs);
MaybeParseMicrosoftAttributes(Attrs);
ParseExternalDeclaration(Attrs);
return Actions.ActOnFinishExportDecl(getCurScope(), ExportDecl,
SourceLocation());
}
BalancedDelimiterTracker T(*this, tok::l_brace);
T.consumeOpen();
// 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))
Diag(ExportLoc, diag::err_export_empty)
<< SourceRange(ExportLoc, Tok.getLocation());
while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
Tok.isNot(tok::eof)) {
ParsedAttributesWithRange Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs);
MaybeParseMicrosoftAttributes(Attrs);
ParseExternalDeclaration(Attrs);
}
T.consumeClose();
return Actions.ActOnFinishExportDecl(getCurScope(), ExportDecl,
T.getCloseLocation());
}
/// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or
/// using-directive. Assumes that current token is 'using'.
Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,

View File

@ -770,11 +770,17 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
: Sema::PCC_Namespace);
cutOffParsing();
return nullptr;
case tok::kw_export:
if (getLangOpts().ModulesTS) {
SingleDecl = ParseExportDeclaration();
break;
}
// This must be 'export template'. Parse it so we can diagnose our lack
// of support.
case tok::kw_using:
case tok::kw_namespace:
case tok::kw_typedef:
case tok::kw_template:
case tok::kw_export: // As in 'export template'
case tok::kw_static_assert:
case tok::kw__Static_assert:
// A function definition cannot start with any of these keywords.

View File

@ -15422,6 +15422,36 @@ void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc,
VisibleModules.setVisible(Mod, Loc);
}
/// We have parsed the start of an export declaration, including the '{'
/// (if present).
Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
SourceLocation LBraceLoc) {
// FIXME: C++ Modules TS:
// 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.
ExportDecl *D = ExportDecl::Create(Context, CurContext, ExportLoc);
CurContext->addDecl(D);
PushDeclContext(S, D);
return D;
}
/// 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();
return D;
}
void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
IdentifierInfo* AliasName,
SourceLocation PragmaLoc,

View File

@ -1538,8 +1538,8 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
// If this declaration is not at namespace scope nor module-private,
// then it is visible if its lexical parent has a visible definition.
DeclContext *DC = D->getLexicalDeclContext();
if (!D->isModulePrivate() &&
DC && !DC->isFileContext() && !isa<LinkageSpecDecl>(DC)) {
if (!D->isModulePrivate() && DC && !DC->isFileContext() &&
!isa<LinkageSpecDecl>(DC) && !isa<ExportDecl>(DC)) {
// For a parameter, check whether our current template declaration's
// lexical context is visible, not whether there's some other visible
// definition of it, because parameters aren't "within" the definition.

View File

@ -5892,9 +5892,7 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
if (Ctx && Ctx->isExternCContext())
return Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage)
<< TemplateParams->getSourceRange();
while (Ctx && isa<LinkageSpecDecl>(Ctx))
Ctx = Ctx->getParent();
Ctx = Ctx->getRedeclContext();
// C++ [temp]p2:
// A template-declaration can appear only as a namespace scope or

View File

@ -183,6 +183,7 @@ serialization::getDefinitiveDeclContext(const DeclContext *DC) {
case Decl::ExternCContext:
case Decl::Namespace:
case Decl::LinkageSpec:
case Decl::Export:
return nullptr;
// C/C++ tag types can only be defined in one place.
@ -291,6 +292,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::ObjCProperty:
case Decl::ObjCCompatibleAlias:
case Decl::LinkageSpec:
case Decl::Export:
case Decl::ObjCPropertyImpl:
case Decl::PragmaComment:
case Decl::PragmaDetectMismatch:

View File

@ -327,6 +327,7 @@ namespace clang {
void VisitUsingShadowDecl(UsingShadowDecl *D);
void VisitConstructorUsingShadowDecl(ConstructorUsingShadowDecl *D);
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
void VisitExportDecl(ExportDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD);
void VisitImportDecl(ImportDecl *D);
void VisitAccessSpecDecl(AccessSpecDecl *D);
@ -1366,6 +1367,11 @@ void ASTDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
D->setRBraceLoc(ReadSourceLocation(Record, Idx));
}
void ASTDeclReader::VisitExportDecl(ExportDecl *D) {
VisitDecl(D);
D->RBraceLoc = ReadSourceLocation(Record, Idx);
}
void ASTDeclReader::VisitLabelDecl(LabelDecl *D) {
VisitNamedDecl(D);
D->setLocStart(ReadSourceLocation(Record, Idx));
@ -3266,6 +3272,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_LINKAGE_SPEC:
D = LinkageSpecDecl::CreateDeserialized(Context, ID);
break;
case DECL_EXPORT:
D = ExportDecl::CreateDeserialized(Context, ID);
break;
case DECL_LABEL:
D = LabelDecl::CreateDeserialized(Context, ID);
break;

View File

@ -110,6 +110,7 @@ namespace clang {
void VisitUsingShadowDecl(UsingShadowDecl *D);
void VisitConstructorUsingShadowDecl(ConstructorUsingShadowDecl *D);
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
void VisitExportDecl(ExportDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
void VisitImportDecl(ImportDecl *D);
void VisitAccessSpecDecl(AccessSpecDecl *D);
@ -1080,6 +1081,12 @@ void ASTDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
Code = serialization::DECL_LINKAGE_SPEC;
}
void ASTDeclWriter::VisitExportDecl(ExportDecl *D) {
VisitDecl(D);
Record.AddSourceLocation(D->getRBraceLoc());
Code = serialization::DECL_EXPORT;
}
void ASTDeclWriter::VisitLabelDecl(LabelDecl *D) {
VisitNamedDecl(D);
Record.AddSourceLocation(D->getLocStart());

View File

@ -0,0 +1,20 @@
// RUN: %clang_cc1 -fmodules-ts -std=c++1z -triple=x86_64-linux-gnu -emit-module-interface %s -o %t.pcm
// RUN: %clang_cc1 -fmodules-ts -std=c++1z -triple=x86_64-linux-gnu %t.pcm -emit-llvm -o - | FileCheck %s
module FooBar;
export {
// CHECK-LABEL: define i32 @_Z1fv(
int f() { return 0; }
}
// FIXME: Emit global variables and their initializers with this TU.
// Emit an initialization function that other TUs can call, with guard variable.
// FIXME: Mangle non-exported symbols so they don't collide with
// non-exported symbols from other modules?
// FIXME: Formally-internal-linkage symbols that are used from an exported
// symbol need a mangled name and external linkage.
// FIXME: const-qualified variables don't have implicit internal linkage when owned by a module.

View File

@ -1,21 +1,32 @@
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -DTEST=0
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -Dmodule=int -DTEST=1
// RUN: not %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -fmodule-file=%t.pcm -o %t.pcm -DTEST=2 2>&1 | FileCheck %s --check-prefix=CHECK-2
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -fmodule-file=%t.pcm -o %t.pcm -verify -Dfoo=bar -DTEST=3
#if TEST == 0
// expected-no-diagnostics
#endif
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -Dmodule=int -DERRORS
module foo;
#if TEST == 1
// expected-error@-2 {{expected module declaration at start of module interface}}
#elif TEST == 2
// CHECK-2: error: redefinition of module 'foo'
#endif
#ifndef ERRORS
// expected-no-diagnostics
#else
// expected-error@-4 {{expected module declaration at start of module interface}}
int n;
#if TEST == 3
// expected-error@-2 {{redefinition of 'n'}}
// expected-note@-3 {{previous}}
// FIXME: support 'export module X;' and 'export { int n; module X; }'
// FIXME: proclaimed-ownership-declarations?
export {
int a;
int b;
}
export int c;
namespace N {
export void f() {}
}
export struct T {} t;
struct S {
export int n; // expected-error {{expected member name or ';'}}
export static int n; // expected-error {{expected member name or ';'}}
};
void f() {
export int n; // expected-error {{expected expression}}
}
#endif

View File

@ -0,0 +1,68 @@
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -DTEST=0
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -Dmodule=int -DTEST=1
// RUN: not %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -fmodule-file=%t.pcm -o %t.pcm -DTEST=2 2>&1 | FileCheck %s --check-prefix=CHECK-2
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -fmodule-file=%t.pcm -o %t.pcm -verify -Dfoo=bar -DTEST=3
#if TEST == 0
// expected-no-diagnostics
#endif
module foo;
#if TEST == 1
// expected-error@-2 {{expected module declaration at start of module interface}}
#elif TEST == 2
// CHECK-2: error: redefinition of module 'foo'
#endif
static int m; // ok, internal linkage, so no redefinition error
int n;
#if TEST == 3
// expected-error@-2 {{redefinition of '}}
// expected-note@-3 {{previous}}
#endif
#if TEST == 0
export {
int a;
int b;
constexpr int *p = &n;
}
export int c;
namespace N {
export void f() {}
}
export struct T {} t;
#elif TEST == 3
int use_a = a; // expected-error {{declaration of 'a' must be imported from module 'foo' before it is required}}
// expected-note@-13 {{previous}}
#undef foo
import foo;
export {} // expected-error {{export declaration cannot be empty}}
export { ; }
export { static_assert(true); }
// FIXME: These diagnostics are not very good.
export import foo; // expected-error {{expected unqualified-id}}
export { import foo; } // expected-error {{expected unqualified-id}}
int use_b = b;
int use_n = n; // FIXME: this should not be visible, because it is not exported
extern int n;
static_assert(&n == p); // FIXME: these are not the same entity
#endif
#if TEST == 1
struct S {
export int n; // expected-error {{expected member name or ';'}}
export static int n; // expected-error {{expected member name or ';'}}
};
#endif
// FIXME: Exports of declarations without external linkage are disallowed.
// Exports of declarations with non-external-linkage types are disallowed.

View File

@ -5635,6 +5635,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::ObjCImplementation:
case Decl::AccessSpec:
case Decl::LinkageSpec:
case Decl::Export:
case Decl::ObjCPropertyImpl:
case Decl::FileScopeAsm:
case Decl::StaticAssert: