forked from OSchip/llvm-project
C++ Modules TS: Add parsing support for module import declaration.
llvm-svn: 279163
This commit is contained in:
parent
4071b1bac3
commit
49cc1ccb00
|
@ -1023,6 +1023,8 @@ def warn_pragma_unroll_cuda_value_in_parens : Warning<
|
|||
let CategoryName = "Modules Issue" in {
|
||||
def err_module_expected_ident : Error<
|
||||
"expected a module name after module import">;
|
||||
def err_attribute_not_import_attr : Error<
|
||||
"%0 attribute cannot be applied to a module import">;
|
||||
def err_module_expected_semi : Error<
|
||||
"expected ';' after module name">;
|
||||
def err_missing_before_module_end : Error<"expected %0 at end of module">;
|
||||
|
|
|
@ -2116,7 +2116,8 @@ private:
|
|||
// Forbid C++11 attributes that appear on certain syntactic
|
||||
// locations which standard permits but we don't supported yet,
|
||||
// for example, attributes appertain to decl specifiers.
|
||||
void ProhibitCXX11Attributes(ParsedAttributesWithRange &attrs);
|
||||
void ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs,
|
||||
unsigned DiagID);
|
||||
|
||||
/// \brief Skip C++11 attributes and return the end location of the last one.
|
||||
/// \returns SourceLocation() if there are no attributes.
|
||||
|
|
|
@ -712,9 +712,12 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
|
|||
// Note that we do not treat 'import' as a contextual
|
||||
// keyword when we're in a caching lexer, because caching lexers only get
|
||||
// used in contexts where import declarations are disallowed.
|
||||
if (LastTokenWasAt && II.isModulesImport() && !InMacroArgs &&
|
||||
!DisableMacroExpansion &&
|
||||
(getLangOpts().Modules || getLangOpts().DebuggerSupport) &&
|
||||
//
|
||||
// Likewise if this is the C++ Modules TS import keyword.
|
||||
if (((LastTokenWasAt && II.isModulesImport()) ||
|
||||
Identifier.is(tok::kw_import)) &&
|
||||
!InMacroArgs && !DisableMacroExpansion &&
|
||||
(getLangOpts().Modules || getLangOpts().DebuggerSupport) &&
|
||||
CurLexerKind != CLK_CachingLexer) {
|
||||
ModuleImportLoc = Identifier.getLocation();
|
||||
ModuleImportPath.clear();
|
||||
|
@ -782,7 +785,8 @@ void Preprocessor::LexAfterModuleImport(Token &Result) {
|
|||
}
|
||||
|
||||
// If we're expecting a '.' or a ';', and we got a '.', then wait until we
|
||||
// see the next identifier.
|
||||
// see the next identifier. (We can also see a '[[' that begins an
|
||||
// attribute-specifier-seq here under the C++ Modules TS.)
|
||||
if (!ModuleImportExpectsIdentifier && Result.getKind() == tok::period) {
|
||||
ModuleImportExpectsIdentifier = true;
|
||||
CurLexerKind = CLK_LexAfterModuleImport;
|
||||
|
|
|
@ -1407,15 +1407,19 @@ void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
|
|||
<< attrs.Range;
|
||||
}
|
||||
|
||||
void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &attrs) {
|
||||
AttributeList *AttrList = attrs.getList();
|
||||
while (AttrList) {
|
||||
if (AttrList->isCXX11Attribute()) {
|
||||
Diag(AttrList->getLoc(), diag::err_attribute_not_type_attr)
|
||||
<< AttrList->getName();
|
||||
AttrList->setInvalid();
|
||||
void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs,
|
||||
unsigned DiagID) {
|
||||
for (AttributeList *Attr = Attrs.getList(); Attr; Attr = Attr->getNext()) {
|
||||
if (!Attr->isCXX11Attribute())
|
||||
continue;
|
||||
if (Attr->getKind() == AttributeList::UnknownAttribute)
|
||||
Diag(Attr->getLoc(), diag::warn_unknown_attribute_ignored)
|
||||
<< Attr->getName();
|
||||
else {
|
||||
Diag(Attr->getLoc(), DiagID)
|
||||
<< Attr->getName();
|
||||
Attr->setInvalid();
|
||||
}
|
||||
AttrList = AttrList->getNext();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2717,7 +2721,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
// Reject C++11 attributes that appertain to decl specifiers as
|
||||
// we don't support any C++11 attributes that appertain to decl
|
||||
// specifiers. This also conforms to what g++ 4.8 is doing.
|
||||
ProhibitCXX11Attributes(attrs);
|
||||
ProhibitCXX11Attributes(attrs, diag::err_attribute_not_type_attr);
|
||||
|
||||
DS.takeAttributesFrom(attrs);
|
||||
}
|
||||
|
|
|
@ -553,6 +553,10 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
|
|||
HandlePragmaUnused();
|
||||
return false;
|
||||
|
||||
case tok::kw_import:
|
||||
Result = ParseModuleImport(SourceLocation());
|
||||
return false;
|
||||
|
||||
case tok::annot_module_include:
|
||||
Actions.ActOnModuleInclude(Tok.getLocation(),
|
||||
reinterpret_cast<Module *>(
|
||||
|
@ -1996,15 +2000,29 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
|
|||
Braces.consumeClose();
|
||||
}
|
||||
|
||||
/// Parse a module import declaration. This is essentially the same for
|
||||
/// Objective-C and the C++ Modules TS, except for the leading '@' (in ObjC)
|
||||
/// and the trailing optional attributes (in C++).
|
||||
///
|
||||
/// [ObjC] @import declaration:
|
||||
/// '@' 'import' (identifier '.')* ';'
|
||||
/// [ModTS] module-import-declaration:
|
||||
/// 'module' module-name attribute-specifier-seq[opt] ';'
|
||||
/// module-name:
|
||||
/// module-name-qualifier[opt] identifier
|
||||
/// module-name-qualifier:
|
||||
/// module-name-qualifier[opt] identifier '.'
|
||||
Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) {
|
||||
assert(Tok.isObjCAtKeyword(tok::objc_import) &&
|
||||
assert((AtLoc.isInvalid() ? Tok.is(tok::kw_import)
|
||||
: Tok.isObjCAtKeyword(tok::objc_import)) &&
|
||||
"Improper start to module import");
|
||||
SourceLocation ImportLoc = ConsumeToken();
|
||||
SourceLocation StartLoc = AtLoc.isInvalid() ? ImportLoc : AtLoc;
|
||||
|
||||
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
|
||||
|
||||
// Parse the module path.
|
||||
do {
|
||||
while (true) {
|
||||
if (!Tok.is(tok::identifier)) {
|
||||
if (Tok.is(tok::code_completion)) {
|
||||
Actions.CodeCompleteModuleImport(ImportLoc, Path);
|
||||
|
@ -2020,14 +2038,17 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) {
|
|||
// Record this part of the module path.
|
||||
Path.push_back(std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation()));
|
||||
ConsumeToken();
|
||||
|
||||
if (Tok.is(tok::period)) {
|
||||
ConsumeToken();
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
if (Tok.isNot(tok::period))
|
||||
break;
|
||||
|
||||
ConsumeToken();
|
||||
}
|
||||
|
||||
ParsedAttributesWithRange Attrs(AttrFactory);
|
||||
MaybeParseCXX11Attributes(Attrs);
|
||||
// We don't support any module import attributes yet.
|
||||
ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_import_attr);
|
||||
|
||||
if (PP.hadModuleLoaderFatalFailure()) {
|
||||
// With a fatal failure in the module loader, we abort parsing.
|
||||
|
@ -2035,7 +2056,7 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
DeclResult Import = Actions.ActOnModuleImport(AtLoc, ImportLoc, Path);
|
||||
DeclResult Import = Actions.ActOnModuleImport(StartLoc, ImportLoc, Path);
|
||||
ExpectAndConsumeSemi(diag::err_module_expected_semi);
|
||||
if (Import.isInvalid())
|
||||
return nullptr;
|
||||
|
|
|
@ -15178,7 +15178,7 @@ void Sema::diagnoseMisplacedModuleImport(Module *M, SourceLocation ImportLoc) {
|
|||
return checkModuleImportContext(*this, M, ImportLoc, CurContext);
|
||||
}
|
||||
|
||||
DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
|
||||
DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
|
||||
SourceLocation ImportLoc,
|
||||
ModuleIdPath Path) {
|
||||
Module *Mod =
|
||||
|
@ -15213,8 +15213,7 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
|
|||
}
|
||||
|
||||
TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
|
||||
ImportDecl *Import = ImportDecl::Create(Context, TU,
|
||||
AtLoc.isValid()? AtLoc : ImportLoc,
|
||||
ImportDecl *Import = ImportDecl::Create(Context, TU, StartLoc,
|
||||
Mod, IdentifierLocs);
|
||||
if (!ModuleScopes.empty())
|
||||
Context.addModuleInitializer(ModuleScopes.back().Module, Import);
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// RUN: rm -rf %t
|
||||
// RUN: mkdir -p %t
|
||||
// RUN: echo 'int a, b;' > %t/x.h
|
||||
// RUN: echo 'module x { header "x.h" module y {} }' > %t/map
|
||||
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s
|
||||
|
||||
int use_1 = a; // expected-error {{undeclared}}
|
||||
|
||||
import x;
|
||||
|
||||
int use_2 = b; // ok
|
||||
|
||||
import x [[]];
|
||||
import x [[foo]]; // expected-warning {{unknown attribute 'foo' ignored}}
|
||||
import x [[noreturn]]; // expected-error {{'noreturn' attribute cannot be applied to a module import}}
|
||||
import x [[blarg::noreturn]]; // expected-warning {{unknown attribute 'noreturn' ignored}}
|
||||
|
||||
import x.y;
|
||||
import x.; // expected-error {{expected a module name after module import}}
|
||||
import .x; // expected-error {{expected a module name after module import}}
|
||||
|
||||
import blarg; // expected-error {{module 'blarg' not found}}
|
Loading…
Reference in New Issue