forked from OSchip/llvm-project
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:
parent
10037b93e9
commit
8df390f9eb
clang
include/clang
AST
Basic
Parse
Sema
Serialization
lib
AST
CodeGen
Parse
Sema
Serialization
test
tools/libclang
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -1388,6 +1388,8 @@ DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, {
|
|||
|
||||
DEF_TRAVERSE_DECL(LinkageSpecDecl, {})
|
||||
|
||||
DEF_TRAVERSE_DECL(ExportDecl, {})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCPropertyImplDecl, {// FIXME: implement this
|
||||
})
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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.
|
|
@ -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
|
||||
|
|
|
@ -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.
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue