forked from OSchip/llvm-project
[flang][directive] Enforce basic semantic check for all clauses
This patch is a follow up to D94821 to ensure the correct behavior of the general directive structure checker. This patch add the generation of the Enter function declaration for clauses in the TableGen backend. This helps to ensure each clauses declared in the TableGen file has at least a basic check. Reviewed By: kiranchandramohan Differential Revision: https://reviews.llvm.org/D95108
This commit is contained in:
parent
e9514429a0
commit
3f46c209f1
|
@ -344,6 +344,7 @@ CHECK_SIMPLE_CLAUSE(VectorLength, ACCC_vector_length)
|
|||
CHECK_SIMPLE_CLAUSE(Wait, ACCC_wait)
|
||||
CHECK_SIMPLE_CLAUSE(Worker, ACCC_worker)
|
||||
CHECK_SIMPLE_CLAUSE(Write, ACCC_write)
|
||||
CHECK_SIMPLE_CLAUSE(Unknown, ACCC_unknown)
|
||||
|
||||
void AccStructureChecker::Enter(const parser::AccClause::Create &c) {
|
||||
CheckAllowed(llvm::acc::Clause::ACCC_create);
|
||||
|
|
|
@ -66,50 +66,8 @@ public:
|
|||
void Leave(const parser::AccClauseList &);
|
||||
void Enter(const parser::AccClause &);
|
||||
|
||||
void Enter(const parser::AccClause::Auto &);
|
||||
void Enter(const parser::AccClause::Async &);
|
||||
void Enter(const parser::AccClause::Attach &);
|
||||
void Enter(const parser::AccClause::Bind &);
|
||||
void Enter(const parser::AccClause::Capture &);
|
||||
void Enter(const parser::AccClause::Create &);
|
||||
void Enter(const parser::AccClause::Collapse &);
|
||||
void Enter(const parser::AccClause::Copy &);
|
||||
void Enter(const parser::AccClause::Copyin &);
|
||||
void Enter(const parser::AccClause::Copyout &);
|
||||
void Enter(const parser::AccClause::Default &);
|
||||
void Enter(const parser::AccClause::DefaultAsync &);
|
||||
void Enter(const parser::AccClause::Delete &);
|
||||
void Enter(const parser::AccClause::Detach &);
|
||||
void Enter(const parser::AccClause::Device &);
|
||||
void Enter(const parser::AccClause::DeviceNum &);
|
||||
void Enter(const parser::AccClause::Deviceptr &);
|
||||
void Enter(const parser::AccClause::DeviceResident &);
|
||||
void Enter(const parser::AccClause::DeviceType &);
|
||||
void Enter(const parser::AccClause::Finalize &);
|
||||
void Enter(const parser::AccClause::Firstprivate &);
|
||||
void Enter(const parser::AccClause::Gang &);
|
||||
void Enter(const parser::AccClause::Host &);
|
||||
void Enter(const parser::AccClause::If &);
|
||||
void Enter(const parser::AccClause::IfPresent &);
|
||||
void Enter(const parser::AccClause::Independent &);
|
||||
void Enter(const parser::AccClause::Link &);
|
||||
void Enter(const parser::AccClause::NoCreate &);
|
||||
void Enter(const parser::AccClause::Nohost &);
|
||||
void Enter(const parser::AccClause::NumGangs &);
|
||||
void Enter(const parser::AccClause::NumWorkers &);
|
||||
void Enter(const parser::AccClause::Present &);
|
||||
void Enter(const parser::AccClause::Private &);
|
||||
void Enter(const parser::AccClause::Read &);
|
||||
void Enter(const parser::AccClause::Reduction &);
|
||||
void Enter(const parser::AccClause::Self &);
|
||||
void Enter(const parser::AccClause::Seq &);
|
||||
void Enter(const parser::AccClause::Tile &);
|
||||
void Enter(const parser::AccClause::UseDevice &);
|
||||
void Enter(const parser::AccClause::Vector &);
|
||||
void Enter(const parser::AccClause::VectorLength &);
|
||||
void Enter(const parser::AccClause::Wait &);
|
||||
void Enter(const parser::AccClause::Worker &);
|
||||
void Enter(const parser::AccClause::Write &);
|
||||
#define GEN_FLANG_CLAUSE_CHECK_ENTER
|
||||
#include "llvm/Frontend/OpenACC/ACC.inc"
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -472,15 +472,37 @@ void OmpStructureChecker::Enter(const parser::OmpClause &x) {
|
|||
SetContextClause(x);
|
||||
}
|
||||
|
||||
// Following clauses do not have a seperate node in parse-tree.h.
|
||||
// They fall under 'struct OmpClause' in parse-tree.h.
|
||||
// Following clauses do not have a separate node in parse-tree.h.
|
||||
CHECK_SIMPLE_CLAUSE(AcqRel, OMPC_acq_rel)
|
||||
CHECK_SIMPLE_CLAUSE(Acquire, OMPC_acquire)
|
||||
CHECK_SIMPLE_CLAUSE(AtomicDefaultMemOrder, OMPC_atomic_default_mem_order)
|
||||
CHECK_SIMPLE_CLAUSE(Affinity, OMPC_affinity)
|
||||
CHECK_SIMPLE_CLAUSE(Allocate, OMPC_allocate)
|
||||
CHECK_SIMPLE_CLAUSE(Capture, OMPC_capture)
|
||||
CHECK_SIMPLE_CLAUSE(Copyin, OMPC_copyin)
|
||||
CHECK_SIMPLE_CLAUSE(Copyprivate, OMPC_copyprivate)
|
||||
CHECK_SIMPLE_CLAUSE(Default, OMPC_default)
|
||||
CHECK_SIMPLE_CLAUSE(Depobj, OMPC_depobj)
|
||||
CHECK_SIMPLE_CLAUSE(Destroy, OMPC_destroy)
|
||||
CHECK_SIMPLE_CLAUSE(Detach, OMPC_detach)
|
||||
CHECK_SIMPLE_CLAUSE(Device, OMPC_device)
|
||||
CHECK_SIMPLE_CLAUSE(DeviceType, OMPC_device_type)
|
||||
CHECK_SIMPLE_CLAUSE(DistSchedule, OMPC_dist_schedule)
|
||||
CHECK_SIMPLE_CLAUSE(DynamicAllocators, OMPC_dynamic_allocators)
|
||||
CHECK_SIMPLE_CLAUSE(Exclusive, OMPC_exclusive)
|
||||
CHECK_SIMPLE_CLAUSE(Final, OMPC_final)
|
||||
CHECK_SIMPLE_CLAUSE(Flush, OMPC_flush)
|
||||
CHECK_SIMPLE_CLAUSE(From, OMPC_from)
|
||||
CHECK_SIMPLE_CLAUSE(Hint, OMPC_hint)
|
||||
CHECK_SIMPLE_CLAUSE(InReduction, OMPC_in_reduction)
|
||||
CHECK_SIMPLE_CLAUSE(Inclusive, OMPC_inclusive)
|
||||
CHECK_SIMPLE_CLAUSE(Match, OMPC_match)
|
||||
CHECK_SIMPLE_CLAUSE(Nontemporal, OMPC_nontemporal)
|
||||
CHECK_SIMPLE_CLAUSE(Order, OMPC_order)
|
||||
CHECK_SIMPLE_CLAUSE(Read, OMPC_read)
|
||||
CHECK_SIMPLE_CLAUSE(ReverseOffload, OMPC_reverse_offload)
|
||||
CHECK_SIMPLE_CLAUSE(Threadprivate, OMPC_threadprivate)
|
||||
CHECK_SIMPLE_CLAUSE(Threads, OMPC_threads)
|
||||
CHECK_SIMPLE_CLAUSE(Inbranch, OMPC_inbranch)
|
||||
CHECK_SIMPLE_CLAUSE(IsDevicePtr, OMPC_is_device_ptr)
|
||||
CHECK_SIMPLE_CLAUSE(Lastprivate, OMPC_lastprivate)
|
||||
|
@ -489,20 +511,24 @@ CHECK_SIMPLE_CLAUSE(Mergeable, OMPC_mergeable)
|
|||
CHECK_SIMPLE_CLAUSE(Nogroup, OMPC_nogroup)
|
||||
CHECK_SIMPLE_CLAUSE(Notinbranch, OMPC_notinbranch)
|
||||
CHECK_SIMPLE_CLAUSE(Nowait, OMPC_nowait)
|
||||
CHECK_SIMPLE_CLAUSE(ProcBind, OMPC_proc_bind)
|
||||
CHECK_SIMPLE_CLAUSE(Reduction, OMPC_reduction)
|
||||
CHECK_SIMPLE_CLAUSE(TaskReduction, OMPC_task_reduction)
|
||||
CHECK_SIMPLE_CLAUSE(To, OMPC_to)
|
||||
CHECK_SIMPLE_CLAUSE(Uniform, OMPC_uniform)
|
||||
CHECK_SIMPLE_CLAUSE(Untied, OMPC_untied)
|
||||
CHECK_SIMPLE_CLAUSE(UseDevicePtr, OMPC_use_device_ptr)
|
||||
CHECK_SIMPLE_CLAUSE(AcqRel, OMPC_acq_rel)
|
||||
CHECK_SIMPLE_CLAUSE(Acquire, OMPC_acquire)
|
||||
CHECK_SIMPLE_CLAUSE(SeqCst, OMPC_seq_cst)
|
||||
CHECK_SIMPLE_CLAUSE(Release, OMPC_release)
|
||||
CHECK_SIMPLE_CLAUSE(Relaxed, OMPC_relaxed)
|
||||
CHECK_SIMPLE_CLAUSE(Hint, OMPC_hint)
|
||||
CHECK_SIMPLE_CLAUSE(ProcBind, OMPC_proc_bind)
|
||||
CHECK_SIMPLE_CLAUSE(DistSchedule, OMPC_dist_schedule)
|
||||
CHECK_SIMPLE_CLAUSE(SeqCst, OMPC_seq_cst)
|
||||
CHECK_SIMPLE_CLAUSE(Simd, OMPC_simd)
|
||||
CHECK_SIMPLE_CLAUSE(TaskReduction, OMPC_task_reduction)
|
||||
CHECK_SIMPLE_CLAUSE(To, OMPC_to)
|
||||
CHECK_SIMPLE_CLAUSE(UnifiedAddress, OMPC_unified_address)
|
||||
CHECK_SIMPLE_CLAUSE(UnifiedSharedMemory, OMPC_unified_shared_memory)
|
||||
CHECK_SIMPLE_CLAUSE(Uniform, OMPC_uniform)
|
||||
CHECK_SIMPLE_CLAUSE(Unknown, OMPC_unknown)
|
||||
CHECK_SIMPLE_CLAUSE(Untied, OMPC_untied)
|
||||
CHECK_SIMPLE_CLAUSE(UseDevicePtr, OMPC_use_device_ptr)
|
||||
CHECK_SIMPLE_CLAUSE(UsesAllocators, OMPC_uses_allocators)
|
||||
CHECK_SIMPLE_CLAUSE(Update, OMPC_update)
|
||||
CHECK_SIMPLE_CLAUSE(UseDeviceAddr, OMPC_use_device_addr)
|
||||
CHECK_SIMPLE_CLAUSE(Write, OMPC_write)
|
||||
|
||||
CHECK_REQ_SCALAR_INT_CLAUSE(Allocator, OMPC_allocator)
|
||||
CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize)
|
||||
|
@ -615,27 +641,26 @@ void OmpStructureChecker::Leave(const parser::OmpAtomic &) {
|
|||
}
|
||||
// Restrictions specific to each clause are implemented apart from the
|
||||
// generalized restrictions.
|
||||
void OmpStructureChecker::Enter(const parser::OmpAlignedClause &x) {
|
||||
void OmpStructureChecker::Enter(const parser::OmpClause::Aligned &x) {
|
||||
CheckAllowed(llvm::omp::Clause::OMPC_aligned);
|
||||
|
||||
if (const auto &expr{
|
||||
std::get<std::optional<parser::ScalarIntConstantExpr>>(x.t)}) {
|
||||
std::get<std::optional<parser::ScalarIntConstantExpr>>(x.v.t)}) {
|
||||
RequiresConstantPositiveParameter(llvm::omp::Clause::OMPC_aligned, *expr);
|
||||
}
|
||||
// 2.8.1 TODO: list-item attribute check
|
||||
}
|
||||
void OmpStructureChecker::Enter(const parser::OmpDefaultmapClause &x) {
|
||||
void OmpStructureChecker::Enter(const parser::OmpClause::Defaultmap &x) {
|
||||
CheckAllowed(llvm::omp::Clause::OMPC_defaultmap);
|
||||
using VariableCategory = parser::OmpDefaultmapClause::VariableCategory;
|
||||
if (!std::get<std::optional<VariableCategory>>(x.t)) {
|
||||
if (!std::get<std::optional<VariableCategory>>(x.v.t)) {
|
||||
context_.Say(GetContext().clauseSource,
|
||||
"The argument TOFROM:SCALAR must be specified on the DEFAULTMAP "
|
||||
"clause"_err_en_US);
|
||||
}
|
||||
}
|
||||
void OmpStructureChecker::Enter(const parser::OmpIfClause &x) {
|
||||
void OmpStructureChecker::Enter(const parser::OmpClause::If &x) {
|
||||
CheckAllowed(llvm::omp::Clause::OMPC_if);
|
||||
|
||||
using dirNameModifier = parser::OmpIfClause::DirectiveNameModifier;
|
||||
static std::unordered_map<dirNameModifier, OmpDirectiveSet>
|
||||
dirNameModifierMap{{dirNameModifier::Parallel, llvm::omp::parallelSet},
|
||||
|
@ -651,7 +676,7 @@ void OmpStructureChecker::Enter(const parser::OmpIfClause &x) {
|
|||
{dirNameModifier::Task, {llvm::omp::Directive::OMPD_task}},
|
||||
{dirNameModifier::Taskloop, llvm::omp::taskloopSet}};
|
||||
if (const auto &directiveName{
|
||||
std::get<std::optional<dirNameModifier>>(x.t)}) {
|
||||
std::get<std::optional<dirNameModifier>>(x.v.t)}) {
|
||||
auto search{dirNameModifierMap.find(*directiveName)};
|
||||
if (search == dirNameModifierMap.end() ||
|
||||
!search->second.test(GetContext().directive)) {
|
||||
|
@ -666,12 +691,12 @@ void OmpStructureChecker::Enter(const parser::OmpIfClause &x) {
|
|||
}
|
||||
}
|
||||
|
||||
void OmpStructureChecker::Enter(const parser::OmpLinearClause &x) {
|
||||
void OmpStructureChecker::Enter(const parser::OmpClause::Linear &x) {
|
||||
CheckAllowed(llvm::omp::Clause::OMPC_linear);
|
||||
|
||||
// 2.7 Loop Construct Restriction
|
||||
if ((llvm::omp::doSet | llvm::omp::simdSet).test(GetContext().directive)) {
|
||||
if (std::holds_alternative<parser::OmpLinearClause::WithModifier>(x.u)) {
|
||||
if (std::holds_alternative<parser::OmpLinearClause::WithModifier>(x.v.u)) {
|
||||
context_.Say(GetContext().clauseSource,
|
||||
"A modifier may not be specified in a LINEAR clause "
|
||||
"on the %s directive"_err_en_US,
|
||||
|
@ -701,9 +726,10 @@ void OmpStructureChecker::CheckAllowedMapTypes(
|
|||
}
|
||||
}
|
||||
|
||||
void OmpStructureChecker::Enter(const parser::OmpMapClause &x) {
|
||||
void OmpStructureChecker::Enter(const parser::OmpClause::Map &x) {
|
||||
CheckAllowed(llvm::omp::Clause::OMPC_map);
|
||||
if (const auto &maptype{std::get<std::optional<parser::OmpMapType>>(x.t)}) {
|
||||
|
||||
if (const auto &maptype{std::get<std::optional<parser::OmpMapType>>(x.v.t)}) {
|
||||
using Type = parser::OmpMapType::Type;
|
||||
const Type &type{std::get<Type>(maptype->t)};
|
||||
switch (GetContext().directive) {
|
||||
|
@ -746,13 +772,14 @@ bool OmpStructureChecker::ScheduleModifierHasType(
|
|||
}
|
||||
return false;
|
||||
}
|
||||
void OmpStructureChecker::Enter(const parser::OmpScheduleClause &x) {
|
||||
void OmpStructureChecker::Enter(const parser::OmpClause::Schedule &x) {
|
||||
CheckAllowed(llvm::omp::Clause::OMPC_schedule);
|
||||
const parser::OmpScheduleClause &scheduleClause = x.v;
|
||||
|
||||
// 2.7 Loop Construct Restriction
|
||||
if (llvm::omp::doSet.test(GetContext().directive)) {
|
||||
const auto &kind{std::get<1>(x.t)};
|
||||
const auto &chunk{std::get<2>(x.t)};
|
||||
const auto &kind{std::get<1>(scheduleClause.t)};
|
||||
const auto &chunk{std::get<2>(scheduleClause.t)};
|
||||
if (chunk) {
|
||||
if (kind == parser::OmpScheduleClause::ScheduleType::Runtime ||
|
||||
kind == parser::OmpScheduleClause::ScheduleType::Auto) {
|
||||
|
@ -762,15 +789,15 @@ void OmpStructureChecker::Enter(const parser::OmpScheduleClause &x) {
|
|||
parser::ToUpperCaseLetters(
|
||||
parser::OmpScheduleClause::EnumToString(kind)));
|
||||
}
|
||||
if (const auto &chunkExpr{
|
||||
std::get<std::optional<parser::ScalarIntExpr>>(x.t)}) {
|
||||
if (const auto &chunkExpr{std::get<std::optional<parser::ScalarIntExpr>>(
|
||||
scheduleClause.t)}) {
|
||||
RequiresPositiveParameter(
|
||||
llvm::omp::Clause::OMPC_schedule, *chunkExpr, "chunk size");
|
||||
}
|
||||
}
|
||||
|
||||
if (ScheduleModifierHasType(
|
||||
x, parser::OmpScheduleModifierType::ModType::Nonmonotonic)) {
|
||||
if (ScheduleModifierHasType(scheduleClause,
|
||||
parser::OmpScheduleModifierType::ModType::Nonmonotonic)) {
|
||||
if (kind != parser::OmpScheduleClause::ScheduleType::Dynamic &&
|
||||
kind != parser::OmpScheduleClause::ScheduleType::Guided) {
|
||||
context_.Say(GetContext().clauseSource,
|
||||
|
@ -781,9 +808,9 @@ void OmpStructureChecker::Enter(const parser::OmpScheduleClause &x) {
|
|||
}
|
||||
}
|
||||
|
||||
void OmpStructureChecker::Enter(const parser::OmpDependClause &x) {
|
||||
void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) {
|
||||
CheckAllowed(llvm::omp::Clause::OMPC_depend);
|
||||
if (const auto *inOut{std::get_if<parser::OmpDependClause::InOut>(&x.u)}) {
|
||||
if (const auto *inOut{std::get_if<parser::OmpDependClause::InOut>(&x.v.u)}) {
|
||||
const auto &designators{std::get<std::list<parser::Designator>>(inOut->t)};
|
||||
for (const auto &ele : designators) {
|
||||
if (const auto *dataRef{std::get_if<parser::DataRef>(&ele.u)}) {
|
||||
|
|
|
@ -127,50 +127,6 @@ public:
|
|||
|
||||
void Leave(const parser::OmpClauseList &);
|
||||
void Enter(const parser::OmpClause &);
|
||||
void Enter(const parser::OmpClause::Allocate &);
|
||||
void Enter(const parser::OmpClause::Allocator &);
|
||||
void Enter(const parser::OmpClause::Inbranch &);
|
||||
void Enter(const parser::OmpClause::Mergeable &);
|
||||
void Enter(const parser::OmpClause::Nogroup &);
|
||||
void Enter(const parser::OmpClause::Nowait &);
|
||||
void Enter(const parser::OmpClause::Notinbranch &);
|
||||
void Enter(const parser::OmpClause::Untied &);
|
||||
void Enter(const parser::OmpClause::Collapse &);
|
||||
void Enter(const parser::OmpClause::Copyin &);
|
||||
void Enter(const parser::OmpClause::Copyprivate &);
|
||||
void Enter(const parser::OmpClause::Default &);
|
||||
void Enter(const parser::OmpClause::Device &);
|
||||
void Enter(const parser::OmpClause::DistSchedule &);
|
||||
void Enter(const parser::OmpClause::Final &);
|
||||
void Enter(const parser::OmpClause::Firstprivate &);
|
||||
void Enter(const parser::OmpClause::From &);
|
||||
void Enter(const parser::OmpClause::Grainsize &);
|
||||
void Enter(const parser::OmpClause::Lastprivate &);
|
||||
void Enter(const parser::OmpClause::NumTasks &);
|
||||
void Enter(const parser::OmpClause::NumTeams &);
|
||||
void Enter(const parser::OmpClause::NumThreads &);
|
||||
void Enter(const parser::OmpClause::Ordered &);
|
||||
void Enter(const parser::OmpClause::Priority &);
|
||||
void Enter(const parser::OmpClause::Private &);
|
||||
void Enter(const parser::OmpClause::ProcBind &);
|
||||
void Enter(const parser::OmpClause::Reduction &);
|
||||
void Enter(const parser::OmpClause::Safelen &);
|
||||
void Enter(const parser::OmpClause::Shared &);
|
||||
void Enter(const parser::OmpClause::Simdlen &);
|
||||
void Enter(const parser::OmpClause::TaskReduction &);
|
||||
void Enter(const parser::OmpClause::ThreadLimit &);
|
||||
void Enter(const parser::OmpClause::To &);
|
||||
void Enter(const parser::OmpClause::Link &);
|
||||
void Enter(const parser::OmpClause::Uniform &);
|
||||
void Enter(const parser::OmpClause::UseDevicePtr &);
|
||||
void Enter(const parser::OmpClause::IsDevicePtr &);
|
||||
// Memory-order-clause
|
||||
void Enter(const parser::OmpClause::SeqCst &);
|
||||
void Enter(const parser::OmpClause::AcqRel &);
|
||||
void Enter(const parser::OmpClause::Release &);
|
||||
void Enter(const parser::OmpClause::Acquire &);
|
||||
void Enter(const parser::OmpClause::Relaxed &);
|
||||
void Enter(const parser::OmpClause::Hint &);
|
||||
|
||||
void Enter(const parser::OmpAtomicRead &);
|
||||
void Leave(const parser::OmpAtomicRead &);
|
||||
|
@ -180,13 +136,9 @@ public:
|
|||
void Leave(const parser::OmpAtomicUpdate &);
|
||||
void Enter(const parser::OmpAtomicCapture &);
|
||||
void Leave(const parser::OmpAtomic &);
|
||||
void Enter(const parser::OmpAlignedClause &);
|
||||
void Enter(const parser::OmpDefaultmapClause &);
|
||||
void Enter(const parser::OmpDependClause &);
|
||||
void Enter(const parser::OmpIfClause &);
|
||||
void Enter(const parser::OmpLinearClause &);
|
||||
void Enter(const parser::OmpMapClause &);
|
||||
void Enter(const parser::OmpScheduleClause &);
|
||||
|
||||
#define GEN_FLANG_CLAUSE_CHECK_ENTER
|
||||
#include "llvm/Frontend/OpenMP/OMP.inc"
|
||||
|
||||
private:
|
||||
bool HasInvalidWorksharingNesting(
|
||||
|
|
|
@ -633,6 +633,20 @@ void GenerateFlangClauseUnparse(const DirectiveLanguage &DirLang,
|
|||
}
|
||||
}
|
||||
|
||||
// Generate check in the Enter functions for clauses classes.
|
||||
void GenerateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang,
|
||||
raw_ostream &OS) {
|
||||
|
||||
IfDefScope Scope("GEN_FLANG_CLAUSE_CHECK_ENTER", OS);
|
||||
|
||||
OS << "\n";
|
||||
for (const auto &C : DirLang.getClauses()) {
|
||||
Clause Clause{C};
|
||||
OS << "void Enter(const parser::" << DirLang.getFlangClauseBaseClass()
|
||||
<< "::" << Clause.getFormattedParserClassName() << " &);\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the implementation section for the enumeration in the directive
|
||||
// language
|
||||
void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang,
|
||||
|
@ -649,6 +663,8 @@ void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang,
|
|||
GenerateFlangClauseDump(DirLang, OS);
|
||||
|
||||
GenerateFlangClauseUnparse(DirLang, OS);
|
||||
|
||||
GenerateFlangClauseCheckPrototypes(DirLang, OS);
|
||||
}
|
||||
|
||||
void GenerateClauseClassMacro(const DirectiveLanguage &DirLang,
|
||||
|
|
Loading…
Reference in New Issue