r202615 - Add [extern_c] attribute for modules, allowing a C module to be imported within an extern "C" block in C++ code.
Richard Smith
richard-llvm at metafoo.co.uk
Sat Mar 1 21:58:19 PST 2014
Author: rsmith
Date: Sat Mar 1 23:58:18 2014
New Revision: 202615
URL: http://llvm.org/viewvc/llvm-project?rev=202615&view=rev
Log:
Add [extern_c] attribute for modules, allowing a C module to be imported within an extern "C" block in C++ code.
Added:
cfe/trunk/test/Modules/Inputs/c-header-bad.h
cfe/trunk/test/Modules/Inputs/c-header.h
cfe/trunk/test/Modules/Inputs/cxx-header.h
cfe/trunk/test/Modules/extern_c.cpp
cfe/trunk/test/Modules/extern_c_bad.cpp
Modified:
cfe/trunk/docs/Modules.rst
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Basic/Module.h
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/lib/Basic/Module.cpp
cfe/trunk/lib/Frontend/FrontendActions.cpp
cfe/trunk/lib/Lex/ModuleMap.cpp
cfe/trunk/lib/Parse/ParseDeclCXX.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/test/Modules/Inputs/module.map
Modified: cfe/trunk/docs/Modules.rst
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/Modules.rst?rev=202615&r1=202614&r2=202615&view=diff
==============================================================================
--- cfe/trunk/docs/Modules.rst (original)
+++ cfe/trunk/docs/Modules.rst Sat Mar 1 23:58:18 2014
@@ -245,7 +245,7 @@ As an example, the module map file for t
.. parsed-literal::
- module std [system] {
+ module std [system] [extern_c] {
module complex {
header "complex.h"
export *
@@ -325,7 +325,9 @@ The ``framework`` qualifier specifies th
Resources/ Subdirectory containing additional resources
Name Symbolic link to the shared library for the framework
-The ``system`` attribute specifies that the module is a system module. When a system module is rebuilt, all of the module's header will be considered system headers, which suppresses warnings. This is equivalent to placing ``#pragma GCC system_header`` in each of the module's headers. The form of attributes is described in the section Attributes_, below.
+The ``system`` attribute specifies that the module is a system module. When a system module is rebuilt, all of the module's headers will be considered system headers, which suppresses warnings. This is equivalent to placing ``#pragma GCC system_header`` in each of the module's headers. The form of attributes is described in the section Attributes_, below.
+
+The ``extern_c`` attribute specifies that the module contains C code that can be used from within C++. When such a module is built for use in C++ code, all of the module's headers will be treated as if they were contained within an implicit ``extern "C"`` block. An import for a module with this attribute can appear within an ``extern "C"`` block. No other restrictions are lifted, however: the module currently cannot be imported within an ``extern "C"`` block in a namespace.
Modules can have a number of different kinds of members, each of which is described below:
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=202615&r1=202614&r2=202615&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Mar 1 23:58:18 2014
@@ -6903,6 +6903,14 @@ def err_module_private_declaration : Err
"declaration of %0 must be imported from module '%1' before it is required">;
def err_module_private_definition : Error<
"definition of %0 must be imported from module '%1' before it is required">;
+def err_module_import_in_extern_c : Error<
+ "import of C++ module '%0' appears within extern \"C\" language linkage "
+ "specification">;
+def note_module_import_in_extern_c : Note<
+ "extern \"C\" language linkage specification begins here">;
+def err_module_import_not_at_top_level : Error<
+ "import of module '%0' appears within %1">;
+def note_module_import_not_at_top_level : Note<"%0 begins here">;
}
let CategoryName = "Documentation Issue" in {
Modified: cfe/trunk/include/clang/Basic/Module.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Module.h?rev=202615&r1=202614&r2=202615&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Module.h (original)
+++ cfe/trunk/include/clang/Basic/Module.h Sat Mar 1 23:58:18 2014
@@ -128,7 +128,12 @@ public:
/// \brief Whether this is a "system" module (which assumes that all
/// headers in it are system headers).
unsigned IsSystem : 1;
-
+
+ /// \brief Whether this is an 'extern "C"' module (which implicitly puts all
+ /// headers in it within an 'extern "C"' block, and allows the module to be
+ /// imported within such a block).
+ unsigned IsExternC : 1;
+
/// \brief Whether we should infer submodules for this module based on
/// the headers.
///
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=202615&r1=202614&r2=202615&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Sat Mar 1 23:58:18 2014
@@ -272,6 +272,10 @@ public:
/// ParseTopLevelDecl - Parse one top-level declaration. Returns true if
/// the EOF was encountered.
bool ParseTopLevelDecl(DeclGroupPtrTy &Result);
+ bool ParseTopLevelDecl() {
+ DeclGroupPtrTy Result;
+ return ParseTopLevelDecl(Result);
+ }
/// ConsumeToken - Consume the current 'peek token' and lex the next one.
/// This does not work with special tokens: string literals, code completion
Modified: cfe/trunk/lib/Basic/Module.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Module.cpp?rev=202615&r1=202614&r2=202615&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/Module.cpp (original)
+++ cfe/trunk/lib/Basic/Module.cpp Sat Mar 1 23:58:18 2014
@@ -24,15 +24,14 @@
using namespace clang;
-Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
+Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
bool IsFramework, bool IsExplicit)
: Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent),
Umbrella(), ASTFile(0), IsAvailable(true), IsFromModuleFile(false),
IsFramework(IsFramework), IsExplicit(IsExplicit), IsSystem(false),
- InferSubmodules(false), InferExplicitSubmodules(false),
+ IsExternC(false), InferSubmodules(false), InferExplicitSubmodules(false),
InferExportWildcard(false), ConfigMacrosExhaustive(false),
- NameVisibility(Hidden)
-{
+ NameVisibility(Hidden) {
if (Parent) {
if (!Parent->isAvailable())
IsAvailable = false;
Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=202615&r1=202614&r2=202615&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendActions.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendActions.cpp Sat Mar 1 23:58:18 2014
@@ -130,19 +130,25 @@ operator+=(SmallVectorImpl<char> &Includ
static void addHeaderInclude(StringRef HeaderName,
SmallVectorImpl<char> &Includes,
- const LangOptions &LangOpts) {
+ const LangOptions &LangOpts,
+ bool IsExternC) {
+ if (IsExternC)
+ Includes += "extern \"C\" {\n";
if (LangOpts.ObjC1)
Includes += "#import \"";
else
Includes += "#include \"";
Includes += HeaderName;
Includes += "\"\n";
+ if (IsExternC)
+ Includes += "}\n";
}
static void addHeaderInclude(const FileEntry *Header,
SmallVectorImpl<char> &Includes,
- const LangOptions &LangOpts) {
- addHeaderInclude(Header->getName(), Includes, LangOpts);
+ const LangOptions &LangOpts,
+ bool IsExternC) {
+ addHeaderInclude(Header->getName(), Includes, LangOpts, IsExternC);
}
/// \brief Collect the set of header includes needed to construct the given
@@ -165,7 +171,7 @@ static void collectModuleHeaderIncludes(
for (unsigned I = 0, N = Module->NormalHeaders.size(); I != N; ++I) {
const FileEntry *Header = Module->NormalHeaders[I];
Module->addTopHeader(Header);
- addHeaderInclude(Header, Includes, LangOpts);
+ addHeaderInclude(Header, Includes, LangOpts, Module->IsExternC);
}
// Note that Module->PrivateHeaders will not be a TopHeader.
@@ -173,7 +179,7 @@ static void collectModuleHeaderIncludes(
Module->addTopHeader(UmbrellaHeader);
if (Module->Parent) {
// Include the umbrella header for submodules.
- addHeaderInclude(UmbrellaHeader, Includes, LangOpts);
+ addHeaderInclude(UmbrellaHeader, Includes, LangOpts, Module->IsExternC);
}
} else if (const DirectoryEntry *UmbrellaDir = Module->getUmbrellaDir()) {
// Add all of the headers we find in this subdirectory.
@@ -199,7 +205,7 @@ static void collectModuleHeaderIncludes(
}
// Include this header umbrella header for submodules.
- addHeaderInclude(Dir->path(), Includes, LangOpts);
+ addHeaderInclude(Dir->path(), Includes, LangOpts, Module->IsExternC);
}
}
@@ -267,7 +273,8 @@ bool GenerateModuleAction::BeginSourceFi
// Collect the set of #includes we need to build the module.
SmallString<256> HeaderContents;
if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader())
- addHeaderInclude(UmbrellaHeader, HeaderContents, CI.getLangOpts());
+ addHeaderInclude(UmbrellaHeader, HeaderContents, CI.getLangOpts(),
+ Module->IsExternC);
collectModuleHeaderIncludes(CI.getLangOpts(), FileMgr,
CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(),
Module, HeaderContents);
Modified: cfe/trunk/lib/Lex/ModuleMap.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/ModuleMap.cpp?rev=202615&r1=202614&r2=202615&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/ModuleMap.cpp (original)
+++ cfe/trunk/lib/Lex/ModuleMap.cpp Sat Mar 1 23:58:18 2014
@@ -906,11 +906,14 @@ namespace clang {
/// \brief The set of attributes that can be attached to a module.
struct Attributes {
- Attributes() : IsSystem(), IsExhaustive() { }
+ Attributes() : IsSystem(), IsExternC(), IsExhaustive() { }
/// \brief Whether this is a system module.
unsigned IsSystem : 1;
+ /// \brief Whether this is an extern "C" module.
+ unsigned IsExternC : 1;
+
/// \brief Whether this is an exhaustive set of configuration macros.
unsigned IsExhaustive : 1;
};
@@ -1178,6 +1181,8 @@ namespace {
AT_unknown,
/// \brief The 'system' attribute.
AT_system,
+ /// \brief The 'extern_c' attribute.
+ AT_extern_c,
/// \brief The 'exhaustive' attribute.
AT_exhaustive
};
@@ -1334,7 +1339,9 @@ void ModuleMapParser::parseModuleDecl()
ActiveModule->DefinitionLoc = ModuleNameLoc;
if (Attrs.IsSystem || IsSystem)
ActiveModule->IsSystem = true;
-
+ if (Attrs.IsExternC)
+ ActiveModule->IsExternC = true;
+
bool Done = false;
do {
switch (Tok.Kind) {
@@ -2097,6 +2104,7 @@ bool ModuleMapParser::parseOptionalAttri
AttributeKind Attribute
= llvm::StringSwitch<AttributeKind>(Tok.getString())
.Case("exhaustive", AT_exhaustive)
+ .Case("extern_c", AT_extern_c)
.Case("system", AT_system)
.Default(AT_unknown);
switch (Attribute) {
@@ -2109,6 +2117,10 @@ bool ModuleMapParser::parseOptionalAttri
Attrs.IsSystem = true;
break;
+ case AT_extern_c:
+ Attrs.IsExternC = true;
+ break;
+
case AT_exhaustive:
Attrs.IsExhaustive = true;
break;
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=202615&r1=202614&r2=202615&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Sat Mar 1 23:58:18 2014
@@ -313,11 +313,42 @@ Decl *Parser::ParseLinkage(ParsingDeclSp
BalancedDelimiterTracker T(*this, tok::l_brace);
T.consumeOpen();
- while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
- ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX11Attributes(attrs);
- MaybeParseMicrosoftAttributes(attrs);
- ParseExternalDeclaration(attrs);
+
+ unsigned NestedModules = 0;
+ while (true) {
+ switch (Tok.getKind()) {
+ case tok::annot_module_begin:
+ ++NestedModules;
+ ParseTopLevelDecl();
+ continue;
+
+ case tok::annot_module_end:
+ if (!NestedModules)
+ break;
+ --NestedModules;
+ ParseTopLevelDecl();
+ continue;
+
+ case tok::annot_module_include:
+ ParseTopLevelDecl();
+ continue;
+
+ case tok::eof:
+ break;
+
+ case tok::r_brace:
+ if (!NestedModules)
+ break;
+ // Fall through.
+ default:
+ ParsedAttributesWithRange attrs(AttrFactory);
+ MaybeParseCXX11Attributes(attrs);
+ MaybeParseMicrosoftAttributes(attrs);
+ ParseExternalDeclaration(attrs);
+ continue;
+ }
+
+ break;
}
T.consumeClose();
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=202615&r1=202614&r2=202615&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Mar 1 23:58:18 2014
@@ -12957,6 +12957,36 @@ Decl *Sema::ActOnFileScopeAsmDecl(Expr *
return New;
}
+static void checkModuleImportContext(Sema &S, Module *M,
+ SourceLocation ImportLoc,
+ DeclContext *DC) {
+ if (auto *LSD = dyn_cast<LinkageSpecDecl>(DC)) {
+ switch (LSD->getLanguage()) {
+ case LinkageSpecDecl::lang_c:
+ if (!M->IsExternC) {
+ S.Diag(ImportLoc, diag::err_module_import_in_extern_c)
+ << M->getFullModuleName();
+ S.Diag(LSD->getLocStart(), diag::note_module_import_in_extern_c);
+ return;
+ }
+ break;
+ case LinkageSpecDecl::lang_cxx:
+ break;
+ }
+ DC = LSD->getParent();
+ }
+
+ while (isa<LinkageSpecDecl>(DC))
+ DC = DC->getParent();
+ if (!isa<TranslationUnitDecl>(DC)) {
+ S.Diag(ImportLoc, diag::err_module_import_not_at_top_level)
+ << M->getFullModuleName() << DC;
+ S.Diag(cast<Decl>(DC)->getLocStart(),
+ diag::note_module_import_not_at_top_level)
+ << DC;
+ }
+}
+
DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
SourceLocation ImportLoc,
ModuleIdPath Path) {
@@ -12965,7 +12995,9 @@ DeclResult Sema::ActOnModuleImport(Sourc
/*IsIncludeDirective=*/false);
if (!Mod)
return true;
-
+
+ checkModuleImportContext(*this, Mod, ImportLoc, CurContext);
+
SmallVector<SourceLocation, 2> IdentifierLocs;
Module *ModCheck = Mod;
for (unsigned I = 0, N = Path.size(); I != N; ++I) {
@@ -12987,6 +13019,8 @@ DeclResult Sema::ActOnModuleImport(Sourc
}
void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
+ checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext);
+
// FIXME: Should we synthesize an ImportDecl here?
PP.getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, DirectiveLoc,
/*Complain=*/true);
Added: cfe/trunk/test/Modules/Inputs/c-header-bad.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/c-header-bad.h?rev=202615&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/c-header-bad.h (added)
+++ cfe/trunk/test/Modules/Inputs/c-header-bad.h Sat Mar 1 23:58:18 2014
@@ -0,0 +1,4 @@
+} // expected-error {{extraneous closing brace ('}')}}
+int not_in_extern_c;
+extern "C" { // expected-note {{to match this '{'}}
+// expected-error {{expected '}'}}
Added: cfe/trunk/test/Modules/Inputs/c-header.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/c-header.h?rev=202615&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/c-header.h (added)
+++ cfe/trunk/test/Modules/Inputs/c-header.h Sat Mar 1 23:58:18 2014
@@ -0,0 +1 @@
+int f(void);
Added: cfe/trunk/test/Modules/Inputs/cxx-header.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/cxx-header.h?rev=202615&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/cxx-header.h (added)
+++ cfe/trunk/test/Modules/Inputs/cxx-header.h Sat Mar 1 23:58:18 2014
@@ -0,0 +1 @@
+int f();
Modified: cfe/trunk/test/Modules/Inputs/module.map
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/module.map?rev=202615&r1=202614&r2=202615&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/module.map (original)
+++ cfe/trunk/test/Modules/Inputs/module.map Sat Mar 1 23:58:18 2014
@@ -1,3 +1,6 @@
+module c_library [extern_c] { header "c-header.h" }
+module cxx_library { header "cxx-header.h" requires cplusplus }
+module c_library_bad [extern_c] { header "c-header-bad.h" }
module diamond_top { header "diamond_top.h" }
module diamond_left {
header "diamond_left.h"
Added: cfe/trunk/test/Modules/extern_c.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/extern_c.cpp?rev=202615&view=auto
==============================================================================
--- cfe/trunk/test/Modules/extern_c.cpp (added)
+++ cfe/trunk/test/Modules/extern_c.cpp Sat Mar 1 23:58:18 2014
@@ -0,0 +1,66 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -verify -fmodules-cache-path=%t -I %S/Inputs %s
+// RUN: %clang_cc1 -fmodules -verify -fmodules-cache-path=%t -I %S/Inputs %s -DEXTERN_C
+// RUN: %clang_cc1 -fmodules -verify -fmodules-cache-path=%t -I %S/Inputs %s -DEXTERN_CXX
+// RUN: %clang_cc1 -fmodules -verify -fmodules-cache-path=%t -I %S/Inputs %s -DEXTERN_C -DEXTERN_CXX
+// RUN: %clang_cc1 -fmodules -verify -fmodules-cache-path=%t -I %S/Inputs %s -DEXTERN_C -DNAMESPACE
+// RUN: %clang_cc1 -fmodules -verify -fmodules-cache-path=%t -I %S/Inputs %s -DCXX_HEADER
+// RUN: %clang_cc1 -fmodules -verify -fmodules-cache-path=%t -I %S/Inputs %s -DCXX_HEADER -DEXTERN_C
+// RUN: %clang_cc1 -fmodules -verify -fmodules-cache-path=%t -I %S/Inputs %s -DCXX_HEADER -DEXTERN_CXX
+// RUN: %clang_cc1 -fmodules -verify -fmodules-cache-path=%t -I %S/Inputs %s -DCXX_HEADER -DEXTERN_C -DEXTERN_CXX
+// RUN: %clang_cc1 -fmodules -verify -fmodules-cache-path=%t -I %S/Inputs %s -DCXX_HEADER -DEXTERN_C -DNAMESPACE
+
+#ifdef NAMESPACE
+namespace M {
+#endif
+
+#ifdef EXTERN_C
+extern "C" {
+#endif
+
+#ifdef EXTERN_CXX
+extern "C++" {
+#endif
+
+#ifdef CXX_HEADER
+#define HEADER "cxx-header.h"
+#else
+#define HEADER "c-header.h"
+#endif
+
+#include HEADER
+
+#if defined(EXTERN_C) && !defined(EXTERN_CXX) && defined(CXX_HEADER)
+// expected-error at -3 {{import of C++ module 'cxx_library' appears within extern "C" language linkage specification}}
+// expected-note at -17 {{extern "C" language linkage specification begins here}}
+#elif defined(NAMESPACE)
+// expected-error-re at -6 {{import of module '{{c_library|cxx_library}}' appears within namespace 'M'}}
+// expected-note at -24 {{namespace 'M' begins here}}
+#endif
+
+#ifdef EXTERN_CXX
+}
+#endif
+
+#ifdef EXTERN_C
+}
+#endif
+
+#ifdef NAMESPACE
+}
+using namespace M;
+#endif
+
+namespace N {
+ int k = f();
+
+ extern "C" {
+ int f;
+#if !defined(CXX_HEADER)
+ // expected-error at -2 {{redefinition of 'f' as different kind of symbol}}
+ // expected-note at c-header.h:1 {{previous}}
+#endif
+ }
+}
+
+suppress_expected_no_diagnostics_error; // expected-error {{}}
Added: cfe/trunk/test/Modules/extern_c_bad.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/extern_c_bad.cpp?rev=202615&view=auto
==============================================================================
--- cfe/trunk/test/Modules/extern_c_bad.cpp (added)
+++ cfe/trunk/test/Modules/extern_c_bad.cpp Sat Mar 1 23:58:18 2014
@@ -0,0 +1,2 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -verify -fmodules -x c++ -emit-module -fmodules-cache-path=%t -fmodule-name=c_library_bad %S/Inputs/module.map
More information about the cfe-commits
mailing list