Skip to content

Commit a0d70b5

Browse files
authored
Add language detection support (#839)
1 parent 795f450 commit a0d70b5

7 files changed

Lines changed: 289 additions & 3 deletions

File tree

include/CppInterOp/CppInterOp.h

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,69 @@ enum QualKind : unsigned char {
102102
Restrict = 1 << 2
103103
};
104104

105+
/// Enum modelling programming languages.
106+
enum class InterpreterLanguage : unsigned char {
107+
Unknown,
108+
Asm,
109+
CIR,
110+
LLVM_IR,
111+
C,
112+
CPlusPlus,
113+
ObjC,
114+
ObjCPlusPlus,
115+
OpenCL,
116+
OpenCLCXX,
117+
CUDA,
118+
HIP,
119+
HLSL
120+
};
121+
122+
/// Enum modelling language standards.
123+
enum class InterpreterLanguageStandard : unsigned char {
124+
c89,
125+
c94,
126+
gnu89,
127+
c99,
128+
gnu99,
129+
c11,
130+
gnu11,
131+
c17,
132+
gnu17,
133+
c23,
134+
gnu23,
135+
c2y,
136+
gnu2y,
137+
cxx98,
138+
gnucxx98,
139+
cxx11,
140+
gnucxx11,
141+
cxx14,
142+
gnucxx14,
143+
cxx17,
144+
gnucxx17,
145+
cxx20,
146+
gnucxx20,
147+
cxx23,
148+
gnucxx23,
149+
cxx26,
150+
gnucxx26,
151+
opencl10,
152+
opencl11,
153+
opencl12,
154+
opencl20,
155+
opencl30,
156+
openclcpp10,
157+
openclcpp2021,
158+
hlsl,
159+
hlsl2015,
160+
hlsl2016,
161+
hlsl2017,
162+
hlsl2018,
163+
hlsl2021,
164+
hlsl202x,
165+
hlsl202y,
166+
lang_unspecified
167+
};
105168
inline QualKind operator|(QualKind a, QualKind b) {
106169
return static_cast<QualKind>(static_cast<unsigned char>(a) |
107170
static_cast<unsigned char>(b));
@@ -728,6 +791,13 @@ CPPINTEROP_API bool ActivateInterpreter(TInterp_t I);
728791
///\returns the current interpreter instance, if any.
729792
CPPINTEROP_API TInterp_t GetInterpreter();
730793

794+
/// Returns the programming language of the interpreter.
795+
CPPINTEROP_API InterpreterLanguage GetLanguage(TInterp_t I = nullptr);
796+
797+
/// Returns the language standard of the interpreter.
798+
CPPINTEROP_API InterpreterLanguageStandard
799+
GetLanguageStandard(TInterp_t I = nullptr);
800+
731801
/// Sets the Interpreter instance with an external interpreter, meant to
732802
/// be called by an external library that manages it's own interpreter.
733803
/// Sets a flag signifying CppInterOp does not have ownership of the

include/CppInterOp/Dispatch.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ extern "C" CPPINTEROP_API CppFnPtrTy CppGetProcAddress(const char* procname);
6363
DISPATCH_API(IsEnumType, decltype(&CppImpl::IsEnumType)) \
6464
DISPATCH_API(GetIntegerTypeFromEnumType, \
6565
decltype(&CppImpl::GetIntegerTypeFromEnumType)) \
66+
DISPATCH_API(GetLanguage, decltype(&CppImpl::GetLanguage)) \
67+
DISPATCH_API(GetLanguageStandard, decltype(&CppImpl::GetLanguageStandard)) \
6668
DISPATCH_API(GetReferencedType, decltype(&CppImpl::GetReferencedType)) \
6769
DISPATCH_API(IsPointerType, decltype(&CppImpl::IsPointerType)) \
6870
DISPATCH_API(GetPointeeType, decltype(&CppImpl::GetPointeeType)) \

include/clang-c/CXCppInterOp.h

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,74 @@ typedef enum {
8787
CXInterpreter_MoreInputExpected = 2,
8888
} CXInterpreter_CompilationResult;
8989

90+
/**
91+
* Enum to represent the programming language of the interpreter.
92+
*/
93+
typedef enum {
94+
CXInterpreterLanguage_Unknown,
95+
CXInterpreterLanguage_Asm,
96+
CXInterpreterLanguage_CIR,
97+
CXInterpreterLanguage_LLVM_IR,
98+
CXInterpreterLanguage_C,
99+
CXInterpreterLanguage_CPlusPlus,
100+
CXInterpreterLanguage_ObjC,
101+
CXInterpreterLanguage_ObjCPlusPlus,
102+
CXInterpreterLanguage_OpenCL,
103+
CXInterpreterLanguage_OpenCLCXX,
104+
CXInterpreterLanguage_CUDA,
105+
CXInterpreterLanguage_HIP,
106+
CXInterpreterLanguage_HLSL
107+
} CXInterpreterLanguage;
108+
109+
/**
110+
* Enum to represent the language standard of the interpreter.
111+
*/
112+
typedef enum {
113+
CXInterpreterLanguageStandard_c89,
114+
CXInterpreterLanguageStandard_c94,
115+
CXInterpreterLanguageStandard_gnu89,
116+
CXInterpreterLanguageStandard_c99,
117+
CXInterpreterLanguageStandard_gnu99,
118+
CXInterpreterLanguageStandard_c11,
119+
CXInterpreterLanguageStandard_gnu11,
120+
CXInterpreterLanguageStandard_c17,
121+
CXInterpreterLanguageStandard_gnu17,
122+
CXInterpreterLanguageStandard_c23,
123+
CXInterpreterLanguageStandard_gnu23,
124+
CXInterpreterLanguageStandard_c2y,
125+
CXInterpreterLanguageStandard_gnu2y,
126+
CXInterpreterLanguageStandard_cxx98,
127+
CXInterpreterLanguageStandard_gnucxx98,
128+
CXInterpreterLanguageStandard_cxx11,
129+
CXInterpreterLanguageStandard_gnucxx11,
130+
CXInterpreterLanguageStandard_cxx14,
131+
CXInterpreterLanguageStandard_gnucxx14,
132+
CXInterpreterLanguageStandard_cxx17,
133+
CXInterpreterLanguageStandard_gnucxx17,
134+
CXInterpreterLanguageStandard_cxx20,
135+
CXInterpreterLanguageStandard_gnucxx20,
136+
CXInterpreterLanguageStandard_cxx23,
137+
CXInterpreterLanguageStandard_gnucxx23,
138+
CXInterpreterLanguageStandard_cxx26,
139+
CXInterpreterLanguageStandard_gnucxx26,
140+
CXInterpreterLanguageStandard_opencl10,
141+
CXInterpreterLanguageStandard_opencl11,
142+
CXInterpreterLanguageStandard_opencl12,
143+
CXInterpreterLanguageStandard_opencl20,
144+
CXInterpreterLanguageStandard_opencl30,
145+
CXInterpreterLanguageStandard_openclcpp10,
146+
CXInterpreterLanguageStandard_openclcpp2021,
147+
CXInterpreterLanguageStandard_hlsl,
148+
CXInterpreterLanguageStandard_hlsl2015,
149+
CXInterpreterLanguageStandard_hlsl2016,
150+
CXInterpreterLanguageStandard_hlsl2017,
151+
CXInterpreterLanguageStandard_hlsl2018,
152+
CXInterpreterLanguageStandard_hlsl2021,
153+
CXInterpreterLanguageStandard_hlsl202x,
154+
CXInterpreterLanguageStandard_hlsl202y,
155+
CXInterpreterLanguageStandard_lang_unspecified
156+
} CXInterpreterLanguageStandard;
157+
90158
/**
91159
* Add a search path to the interpreter.
92160
*
@@ -210,6 +278,26 @@ CINDEX_LINKAGE CXInterpreter_CompilationResult clang_Interpreter_loadLibrary(
210278
CINDEX_LINKAGE void clang_Interpreter_unloadLibrary(CXInterpreter I,
211279
const char* lib_stem);
212280

281+
/**
282+
* Returns the programming language of the interpreter.
283+
*
284+
* \param I The interpreter.
285+
*
286+
* \returns CXInterpreterLanguage value.
287+
*/
288+
CINDEX_LINKAGE CXInterpreterLanguage
289+
clang_Interpreter_getLanguage(CXInterpreter I);
290+
291+
/**
292+
* Returns the language standard of the interpreter.
293+
*
294+
* \param I The interpreter.
295+
*
296+
* \returns CXInterpreterLanguageStandard value.
297+
*/
298+
CINDEX_LINKAGE CXInterpreterLanguageStandard
299+
clang_Interpreter_getLanguageStandard(CXInterpreter I);
300+
213301
/**
214302
* @}
215303
*/

lib/CppInterOp/CXCppInterOp.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,17 @@ void clang_Interpreter_unloadLibrary(CXInterpreter I, const char* lib_stem) {
397397
interp->getDynamicLibraryManager()->unloadLibrary(lib_stem);
398398
}
399399

400+
CXInterpreterLanguage clang_Interpreter_getLanguage(CXInterpreter I) {
401+
return static_cast<CXInterpreterLanguage>(
402+
Cpp::GetLanguage(getInterpreter(I)));
403+
}
404+
405+
CXInterpreterLanguageStandard
406+
clang_Interpreter_getLanguageStandard(CXInterpreter I) {
407+
return static_cast<CXInterpreterLanguageStandard>(
408+
Cpp::GetLanguageStandard(getInterpreter(I)));
409+
}
410+
400411
CXString clang_Interpreter_searchLibrariesForSymbol(CXInterpreter I,
401412
const char* mangled_name,
402413
bool search_system) {

lib/CppInterOp/CppInterOp.cpp

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "clang/AST/Stmt.h"
3131
#include "clang/AST/Type.h"
3232
#include "clang/Basic/DiagnosticSema.h"
33+
#include "clang/Basic/LangStandard.h"
3334
#include "clang/Basic/Linkage.h"
3435
#include "clang/Basic/OperatorKinds.h"
3536
#include "clang/Basic/SourceLocation.h"
@@ -164,11 +165,14 @@ struct InterpreterInfo {
164165
// std::deque avoids relocations and calling the dtor of InterpreterInfo.
165166
static llvm::ManagedStatic<std::deque<InterpreterInfo>> sInterpreters;
166167

167-
static compat::Interpreter& getInterp() {
168+
static compat::Interpreter& getInterp(TInterp_t I = nullptr) {
169+
if (I)
170+
return *static_cast<compat::Interpreter*>(I);
168171
assert(!sInterpreters->empty() &&
169172
"Interpreter instance must be set before calling this!");
170173
return *sInterpreters->back().Interpreter;
171174
}
175+
172176
static clang::Sema& getSema() { return getInterp().getCI()->getSema(); }
173177
static clang::ASTContext& getASTContext() { return getSema().getASTContext(); }
174178

@@ -3414,7 +3418,8 @@ TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
34143418
if (!T.isWasm())
34153419
AddLibrarySearchPaths(ResourceDir, I);
34163420

3417-
I->declare(R"(
3421+
if (GetLanguage(I) != InterpreterLanguage::C) {
3422+
I->declare(R"(
34183423
namespace __internal_CppInterOp {
34193424
template <typename Signature>
34203425
struct function;
@@ -3424,6 +3429,7 @@ TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
34243429
};
34253430
} // namespace __internal_CppInterOp
34263431
)");
3432+
}
34273433

34283434
sInterpreters->emplace_back(I, /*Owned=*/true);
34293435

@@ -3440,7 +3446,7 @@ TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
34403446
// obtain mangled name
34413447
auto* D = static_cast<clang::Decl*>(
34423448
Cpp::GetNamed("__clang_Interpreter_SetValueWithAlloc"));
3443-
if (auto* FD = llvm::dyn_cast<FunctionDecl>(D)) {
3449+
if (auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D)) {
34443450
auto GD = GlobalDecl(FD);
34453451
std::string mangledName;
34463452
compat::maybeMangleDeclName(GD, mangledName);
@@ -3495,6 +3501,31 @@ TInterp_t GetInterpreter() {
34953501
return sInterpreters->back().Interpreter;
34963502
}
34973503

3504+
InterpreterLanguage GetLanguage(TInterp_t I /*=nullptr*/) {
3505+
compat::Interpreter* interp = &getInterp(I);
3506+
const auto& LO = interp->getCI()->getLangOpts();
3507+
auto standard = clang::LangStandard::getLangStandardForKind(LO.LangStd);
3508+
auto lang = static_cast<InterpreterLanguage>(standard.getLanguage());
3509+
assert(lang != InterpreterLanguage::Unknown && "Unknown language");
3510+
assert(static_cast<unsigned char>(lang) <=
3511+
static_cast<unsigned char>(InterpreterLanguage::HLSL) &&
3512+
"Unhandled Language");
3513+
return lang;
3514+
}
3515+
3516+
InterpreterLanguageStandard GetLanguageStandard(TInterp_t I /*=nullptr*/) {
3517+
compat::Interpreter* interp = &getInterp(I);
3518+
const auto& LO = interp->getCI()->getLangOpts();
3519+
auto langStandard = static_cast<InterpreterLanguageStandard>(LO.LangStd);
3520+
assert(langStandard != InterpreterLanguageStandard::lang_unspecified &&
3521+
"Unspecified language standard");
3522+
assert(static_cast<unsigned char>(langStandard) <=
3523+
static_cast<unsigned char>(
3524+
InterpreterLanguageStandard::lang_unspecified) &&
3525+
"Unhandled language standard.");
3526+
return langStandard;
3527+
}
3528+
34983529
void UseExternalInterpreter(TInterp_t I) {
34993530
assert(sInterpreters->empty() && "sInterpreter already in use!");
35003531
sInterpreters->emplace_back(static_cast<compat::Interpreter*>(I),

unittests/CppInterOp/CUDATest.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,18 @@ TEST(CUDATest, CUDARuntime) {
8080

8181
EXPECT_TRUE(HasCudaRuntime());
8282
}
83+
84+
TEST(CUDATest, Interpreter_GetLanguageCUDA) {
85+
#ifdef _WIN32
86+
GTEST_SKIP() << "Disabled on Windows. Needs fixing.";
87+
#endif
88+
if (!HasCudaRuntime())
89+
GTEST_SKIP() << "Skipping CUDA tests as CUDA runtime not found";
90+
91+
auto* I =
92+
Cpp::CreateInterpreter({}, {"-x", "cuda", "--cuda-path=/usr/local/cuda"});
93+
if (!I) {
94+
GTEST_SKIP() << "Skipping CUDA test as CUDA SDK not found";
95+
}
96+
EXPECT_EQ(Cpp::GetLanguage(nullptr), Cpp::InterpreterLanguage::CUDA);
97+
}

unittests/CppInterOp/InterpreterTest.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,75 @@ TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_CodeCompletion) {
337337
EXPECT_EQ(2U, cnt); // float and foo
338338
}
339339

340+
TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_GetLanguageCpp) {
341+
// Default interpreter (C++14)
342+
TestFixture::CreateInterpreter();
343+
EXPECT_EQ(Cpp::GetLanguage(nullptr), Cpp::InterpreterLanguage::CPlusPlus);
344+
}
345+
346+
TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_GetLanguageStandardCpp) {
347+
// Other C++ standards
348+
TestFixture::CreateInterpreter({"-std=c++14"});
349+
EXPECT_EQ(Cpp::GetLanguageStandard(nullptr),
350+
Cpp::InterpreterLanguageStandard::cxx14);
351+
352+
TestFixture::CreateInterpreter({"-std=c++17"});
353+
EXPECT_EQ(Cpp::GetLanguageStandard(nullptr),
354+
Cpp::InterpreterLanguageStandard::cxx17);
355+
356+
TestFixture::CreateInterpreter({"-std=c++20"});
357+
EXPECT_EQ(Cpp::GetLanguageStandard(nullptr),
358+
Cpp::InterpreterLanguageStandard::cxx20);
359+
360+
TestFixture::CreateInterpreter({"-std=c++23"});
361+
EXPECT_EQ(Cpp::GetLanguageStandard(nullptr),
362+
Cpp::InterpreterLanguageStandard::cxx23);
363+
}
364+
365+
TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_GetLanguageCAPI) {
366+
auto* I = TestFixture::CreateInterpreter();
367+
auto* CXI = clang_createInterpreterFromRawPtr(I);
368+
EXPECT_EQ(clang_Interpreter_getLanguage(CXI),
369+
CXInterpreterLanguage_CPlusPlus);
370+
EXPECT_EQ(clang_Interpreter_getLanguageStandard(CXI),
371+
CXInterpreterLanguageStandard_cxx14);
372+
clang_Interpreter_dispose(CXI);
373+
}
374+
375+
TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_GetLanguageC) {
376+
TestFixture::CreateInterpreter({"-xc", "-std=c99"});
377+
EXPECT_EQ(Cpp::GetLanguage(nullptr), Cpp::InterpreterLanguage::C);
378+
EXPECT_EQ(Cpp::GetLanguageStandard(nullptr),
379+
Cpp::InterpreterLanguageStandard::c99);
380+
}
381+
TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_GetLanguageStandardC) {
382+
TestFixture::CreateInterpreter({"-xc", "-std=c89"});
383+
EXPECT_EQ(Cpp::GetLanguageStandard(nullptr),
384+
Cpp::InterpreterLanguageStandard::c89);
385+
386+
TestFixture::CreateInterpreter({"-xc", "-std=c11"});
387+
EXPECT_EQ(Cpp::GetLanguageStandard(nullptr),
388+
Cpp::InterpreterLanguageStandard::c11);
389+
390+
TestFixture::CreateInterpreter({"-xc", "-std=c17"});
391+
EXPECT_EQ(Cpp::GetLanguageStandard(nullptr),
392+
Cpp::InterpreterLanguageStandard::c17);
393+
394+
TestFixture::CreateInterpreter({"-xc", "-std=c23"});
395+
EXPECT_EQ(Cpp::GetLanguageStandard(nullptr),
396+
Cpp::InterpreterLanguageStandard::c23);
397+
}
398+
399+
TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_GetLanguageStandardGNU) {
400+
TestFixture::CreateInterpreter({"-std=gnu++14"});
401+
EXPECT_EQ(Cpp::GetLanguageStandard(nullptr),
402+
Cpp::InterpreterLanguageStandard::gnucxx14);
403+
404+
TestFixture::CreateInterpreter({"-std=gnu++17"});
405+
EXPECT_EQ(Cpp::GetLanguageStandard(nullptr),
406+
Cpp::InterpreterLanguageStandard::gnucxx17);
407+
}
408+
340409
TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_ExternalInterpreter) {
341410

342411
if (llvm::sys::RunningOnValgrind())

0 commit comments

Comments
 (0)