mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-23 22:00:10 +00:00
[C++20] [Module] Support extern C/C++ semantics
According to [module.unit]p7.2.3, a declaration within a linkage-specification should be attached to the global module. This let user to forward declare types across modules. Reviewed by: rsmith, aaron.ballman Differential Revision: https://reviews.llvm.org/D110215
This commit is contained in:
parent
ec64d10340
commit
e587372f85
@ -153,6 +153,10 @@ public:
|
||||
return Kind == ModuleInterfaceUnit || Kind == PrivateModuleFragment;
|
||||
}
|
||||
|
||||
/// Does this Module scope describe a fragment of the global module within
|
||||
/// some C++ module.
|
||||
bool isGlobalModule() const { return Kind == GlobalModuleFragment; }
|
||||
|
||||
private:
|
||||
/// The submodules of this module, indexed by name.
|
||||
std::vector<Module *> SubModules;
|
||||
|
@ -538,8 +538,11 @@ public:
|
||||
///
|
||||
/// We model the global module fragment as a submodule of the module
|
||||
/// interface unit. Unfortunately, we can't create the module interface
|
||||
/// unit's Module until later, because we don't know what it will be called.
|
||||
Module *createGlobalModuleFragmentForModuleUnit(SourceLocation Loc);
|
||||
/// unit's Module until later, because we don't know what it will be called
|
||||
/// usually. See C++20 [module.unit]/7.2 for the case we could know its
|
||||
/// parent.
|
||||
Module *createGlobalModuleFragmentForModuleUnit(SourceLocation Loc,
|
||||
Module *Parent = nullptr);
|
||||
|
||||
/// Create a global module fragment for a C++ module interface unit.
|
||||
Module *createPrivateModuleFragmentForInterfaceUnit(Module *Parent,
|
||||
|
@ -2222,6 +2222,11 @@ private:
|
||||
return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module;
|
||||
}
|
||||
|
||||
/// Enter the scope of the global module.
|
||||
Module *PushGlobalModuleFragment(SourceLocation BeginLoc, bool IsImplicit);
|
||||
/// Leave the scope of the global module.
|
||||
void PopGlobalModuleFragment();
|
||||
|
||||
VisibleModuleSet VisibleModules;
|
||||
|
||||
public:
|
||||
|
@ -832,12 +832,16 @@ std::pair<Module *, bool> ModuleMap::findOrCreateModule(StringRef Name,
|
||||
return std::make_pair(Result, true);
|
||||
}
|
||||
|
||||
Module *ModuleMap::createGlobalModuleFragmentForModuleUnit(SourceLocation Loc) {
|
||||
PendingSubmodules.emplace_back(
|
||||
new Module("<global>", Loc, nullptr, /*IsFramework*/ false,
|
||||
/*IsExplicit*/ true, NumCreatedModules++));
|
||||
PendingSubmodules.back()->Kind = Module::GlobalModuleFragment;
|
||||
return PendingSubmodules.back().get();
|
||||
Module *ModuleMap::createGlobalModuleFragmentForModuleUnit(SourceLocation Loc,
|
||||
Module *Parent) {
|
||||
auto *Result = new Module("<global>", Loc, Parent, /*IsFramework*/ false,
|
||||
/*IsExplicit*/ true, NumCreatedModules++);
|
||||
Result->Kind = Module::GlobalModuleFragment;
|
||||
// If the created module isn't owned by a parent, send it to PendingSubmodules
|
||||
// to wait for its parent.
|
||||
if (!Result->Parent)
|
||||
PendingSubmodules.emplace_back(Result);
|
||||
return Result;
|
||||
}
|
||||
|
||||
Module *
|
||||
|
@ -16146,6 +16146,20 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc,
|
||||
LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext, ExternLoc,
|
||||
LangStr->getExprLoc(), Language,
|
||||
LBraceLoc.isValid());
|
||||
|
||||
/// C++ [module.unit]p7.2.3
|
||||
/// - Otherwise, if the declaration
|
||||
/// - ...
|
||||
/// - ...
|
||||
/// - appears within a linkage-specification,
|
||||
/// it is attached to the global module.
|
||||
if (getLangOpts().CPlusPlusModules) {
|
||||
Module *GlobalModule =
|
||||
PushGlobalModuleFragment(ExternLoc, /*IsImplicit=*/true);
|
||||
D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate);
|
||||
D->setLocalOwningModule(GlobalModule);
|
||||
}
|
||||
|
||||
CurContext->addDecl(D);
|
||||
PushDeclContext(S, D);
|
||||
return D;
|
||||
@ -16162,6 +16176,10 @@ Decl *Sema::ActOnFinishLinkageSpecification(Scope *S,
|
||||
LinkageSpecDecl* LSDecl = cast<LinkageSpecDecl>(LinkageSpec);
|
||||
LSDecl->setRBraceLoc(RBraceLoc);
|
||||
}
|
||||
|
||||
if (getLangOpts().CPlusPlusModules)
|
||||
PopGlobalModuleFragment();
|
||||
|
||||
PopDeclContext();
|
||||
return LinkageSpec;
|
||||
}
|
||||
|
@ -68,15 +68,8 @@ Sema::ActOnGlobalModuleFragmentDecl(SourceLocation ModuleLoc) {
|
||||
|
||||
// We start in the global module; all those declarations are implicitly
|
||||
// module-private (though they do not have module linkage).
|
||||
auto &Map = PP.getHeaderSearchInfo().getModuleMap();
|
||||
auto *GlobalModule = Map.createGlobalModuleFragmentForModuleUnit(ModuleLoc);
|
||||
assert(GlobalModule && "module creation should not fail");
|
||||
|
||||
// Enter the scope of the global module.
|
||||
ModuleScopes.push_back({});
|
||||
ModuleScopes.back().BeginLoc = ModuleLoc;
|
||||
ModuleScopes.back().Module = GlobalModule;
|
||||
VisibleModules.setVisible(GlobalModule, ModuleLoc);
|
||||
Module *GlobalModule =
|
||||
PushGlobalModuleFragment(ModuleLoc, /*IsImplicit=*/false);
|
||||
|
||||
// All declarations created from now on are owned by the global module.
|
||||
auto *TU = Context.getTranslationUnitDecl();
|
||||
@ -708,3 +701,25 @@ Decl *Sema::ActOnFinishExportDecl(Scope *S, Decl *D, SourceLocation RBraceLoc) {
|
||||
|
||||
return D;
|
||||
}
|
||||
|
||||
Module *Sema::PushGlobalModuleFragment(SourceLocation BeginLoc,
|
||||
bool IsImplicit) {
|
||||
ModuleMap &Map = PP.getHeaderSearchInfo().getModuleMap();
|
||||
Module *GlobalModule =
|
||||
Map.createGlobalModuleFragmentForModuleUnit(BeginLoc, getCurrentModule());
|
||||
assert(GlobalModule && "module creation should not fail");
|
||||
|
||||
// Enter the scope of the global module.
|
||||
ModuleScopes.push_back({BeginLoc, GlobalModule,
|
||||
/*ModuleInterface=*/false,
|
||||
/*ImplicitGlobalModuleFragment=*/IsImplicit});
|
||||
VisibleModules.setVisible(GlobalModule, BeginLoc);
|
||||
|
||||
return GlobalModule;
|
||||
}
|
||||
|
||||
void Sema::PopGlobalModuleFragment() {
|
||||
assert(!ModuleScopes.empty() && getCurrentModule()->isGlobalModule() &&
|
||||
"left the wrong module scope, which is not global module fragment");
|
||||
ModuleScopes.pop_back();
|
||||
}
|
||||
|
8
clang/test/CXX/module/module.unit/p7/Inputs/CPP.cppm
Normal file
8
clang/test/CXX/module/module.unit/p7/Inputs/CPP.cppm
Normal file
@ -0,0 +1,8 @@
|
||||
module;
|
||||
#include "h2.h"
|
||||
export module X;
|
||||
|
||||
extern "C++" class CPP {
|
||||
public:
|
||||
void print() {}
|
||||
};
|
12
clang/test/CXX/module/module.unit/p7/Inputs/h1.h
Normal file
12
clang/test/CXX/module/module.unit/p7/Inputs/h1.h
Normal file
@ -0,0 +1,12 @@
|
||||
extern "C" void foo();
|
||||
extern "C" {
|
||||
void bar();
|
||||
int baz();
|
||||
double double_func();
|
||||
}
|
||||
|
||||
extern "C++" {
|
||||
void bar_cpp();
|
||||
int baz_cpp();
|
||||
double double_func_cpp();
|
||||
}
|
1
clang/test/CXX/module/module.unit/p7/Inputs/h2.h
Normal file
1
clang/test/CXX/module/module.unit/p7/Inputs/h2.h
Normal file
@ -0,0 +1 @@
|
||||
extern "C++" class CPP;
|
1
clang/test/CXX/module/module.unit/p7/Inputs/h4.h
Normal file
1
clang/test/CXX/module/module.unit/p7/Inputs/h4.h
Normal file
@ -0,0 +1 @@
|
||||
extern "C" struct C;
|
1
clang/test/CXX/module/module.unit/p7/Inputs/h5.h
Normal file
1
clang/test/CXX/module/module.unit/p7/Inputs/h5.h
Normal file
@ -0,0 +1 @@
|
||||
extern "C++" int a;
|
35
clang/test/CXX/module/module.unit/p7/t1.cpp
Normal file
35
clang/test/CXX/module/module.unit/p7/t1.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
// RUN: %clang_cc1 -std=c++20 %s -verify
|
||||
// expected-no-diagnostics
|
||||
module;
|
||||
|
||||
#include "Inputs/h1.h"
|
||||
|
||||
export module x;
|
||||
|
||||
extern "C" void foo() {
|
||||
return;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
void bar() {
|
||||
return;
|
||||
}
|
||||
int baz() {
|
||||
return 3;
|
||||
}
|
||||
double double_func() {
|
||||
return 5.0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C++" {
|
||||
void bar_cpp() {
|
||||
return;
|
||||
}
|
||||
int baz_cpp() {
|
||||
return 3;
|
||||
}
|
||||
double double_func_cpp() {
|
||||
return 5.0;
|
||||
}
|
||||
}
|
9
clang/test/CXX/module/module.unit/p7/t2.cpp
Normal file
9
clang/test/CXX/module/module.unit/p7/t2.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
// RUN: %clang_cc1 -std=c++20 %s -verify
|
||||
// expected-no-diagnostics
|
||||
module;
|
||||
|
||||
#include "Inputs/h2.h"
|
||||
|
||||
export module x;
|
||||
|
||||
extern "C++" class CPP {};
|
7
clang/test/CXX/module/module.unit/p7/t3.cpp
Normal file
7
clang/test/CXX/module/module.unit/p7/t3.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
// This tests whether the global module would be created when the program don't declare it explicitly.
|
||||
// RUN: %clang_cc1 -std=c++20 %s -verify
|
||||
// expected-no-diagnostics
|
||||
export module x;
|
||||
|
||||
extern "C" void foo();
|
||||
extern "C++" class CPP {};
|
13
clang/test/CXX/module/module.unit/p7/t4.cpp
Normal file
13
clang/test/CXX/module/module.unit/p7/t4.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
// RUN: %clang_cc1 -std=c++20 %s -verify
|
||||
// expected-no-diagnostics
|
||||
module;
|
||||
|
||||
#include "Inputs/h4.h"
|
||||
|
||||
export module x;
|
||||
|
||||
extern "C" struct C {
|
||||
int a;
|
||||
int b;
|
||||
double d;
|
||||
};
|
9
clang/test/CXX/module/module.unit/p7/t5.cpp
Normal file
9
clang/test/CXX/module/module.unit/p7/t5.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
// RUN: %clang_cc1 -std=c++20 %s -verify
|
||||
// expected-no-diagnostics
|
||||
module;
|
||||
|
||||
#include "Inputs/h4.h"
|
||||
|
||||
export module x;
|
||||
|
||||
extern "C++" int a = 5;
|
15
clang/test/CXX/module/module.unit/p7/t6.cpp
Normal file
15
clang/test/CXX/module/module.unit/p7/t6.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
// RUN: rm -fr %t
|
||||
// RUN: mkdir %t
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %S/Inputs/CPP.cppm -I%S/Inputs -o %t/X.pcm
|
||||
// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %s -verify
|
||||
module;
|
||||
#include "Inputs/h2.h"
|
||||
export module use;
|
||||
import X;
|
||||
void printX(CPP *cpp) {
|
||||
cpp->print(); // expected-error {{'CPP' must be defined before it is used}}
|
||||
// expected-error@-1 {{'CPP' must be defined before it is used}}
|
||||
// expected-error@-2 {{no member named 'print' in 'CPP'}}
|
||||
// expected-note@Inputs/CPP.cppm:5 {{definition here is not reachable}}
|
||||
// expected-note@Inputs/CPP.cppm:5 {{definition here is not reachable}}
|
||||
}
|
7
clang/test/CodeGenCXX/Inputs/module-extern-C.h
Normal file
7
clang/test/CodeGenCXX/Inputs/module-extern-C.h
Normal file
@ -0,0 +1,7 @@
|
||||
extern "C" void foo();
|
||||
extern "C" {
|
||||
void bar();
|
||||
int baz();
|
||||
double double_func();
|
||||
}
|
||||
extern "C++" class CPP;
|
27
clang/test/CodeGenCXX/module-extern-C.cpp
Normal file
27
clang/test/CodeGenCXX/module-extern-C.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-llvm -triple %itanium_abi_triple -o - %s | FileCheck %s
|
||||
|
||||
module;
|
||||
|
||||
#include "Inputs/module-extern-C.h"
|
||||
|
||||
export module x;
|
||||
|
||||
// CHECK: define dso_local void @foo()
|
||||
extern "C" void foo() {
|
||||
return;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
// CHECK: define dso_local void @bar()
|
||||
void bar() {
|
||||
return;
|
||||
}
|
||||
// CHECK: define dso_local i32 @baz()
|
||||
int baz() {
|
||||
return 3;
|
||||
}
|
||||
// CHECK: define dso_local double @double_func()
|
||||
double double_func() {
|
||||
return 5.0;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user