gccrs: Added FFIVector to get Polonius output on C++ side

gcc/rust/ChangeLog:

	* Make-lang.in: Compile new file, rust-polonius.cc
	* checks/errors/borrowck/ffi-polonius/src/gccrs_ffi.rs: Opaque
	type to represent FFIVector from C++.
	* checks/errors/borrowck/ffi-polonius/src/gccrs_ffi_generated.rs:
	Change types of fields in Output.
	* checks/errors/borrowck/ffi-polonius/src/lib.rs: Added helper
	functions to contruct Polonius output on C++ side,
	used helpers to contruct Polonius output on C++ side.
	* checks/errors/borrowck/polonius/rust-polonius-ffi.h (make_vector):
	FFIVector is a wrapper around std::vector for transfering data
	from Rust to C++.
	(struct Output): Use pointers to FFIVector instead of bool to
	store Polonius output data.
	* checks/errors/borrowck/polonius/rust-polonius.h (FFIVector__new):
	Helper function.
	(FFIVector__new_vec_pair): Likewise.
	(FFIVector__new_vec_triple): Likewise.
	(FFIVector__push): Likewise.
	(FFIVector__push_vec_pair): Likewise.
	(FFIVector__push_vec_triple): Likewise.
	* checks/errors/borrowck/rust-borrow-checker.cc (BorrowChecker::go):
	Convert FFIVector to std::vector representation for easier
	navigation.
	* checks/errors/borrowck/polonius/rust-polonius.cc: New file,
	implementation of helper functions.

Signed-off-by: Kushal Pal <kushalpal109@gmail.com>
This commit is contained in:
Kushal Pal 2024-06-05 11:09:10 +00:00 committed by Arthur Cohen
parent e50983a756
commit 29f847e8b8
8 changed files with 259 additions and 14 deletions

View file

@ -171,6 +171,7 @@ GRS_OBJS = \
rust/rust-borrow-checker.o \
rust/rust-bir-builder-expr-stmt.o \
rust/rust-bir-dump.o \
rust/rust-polonius.o\
rust/rust-hir-dot-operator.o \
rust/rust-hir-path-probe.o \
rust/rust-type-util.o \
@ -487,6 +488,12 @@ rust/%.o: rust/checks/errors/borrowck/%.cc
$(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $<
$(POSTCOMPILE)
# build borrow checking pass polonius files in rust folder
rust/%.o: rust/checks/errors/borrowck/polonius/%.cc
$(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $<
$(POSTCOMPILE)
# build rust/metadata files in rust folder
rust/%.o: rust/metadata/%.cc
$(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $<

View file

@ -32,6 +32,11 @@ include!("gccrs_ffi_generated.rs");
use crate::GccrsAtom;
// Using opqaue types
extern "C" {
pub type FFIVector;
}
impl<T1, T2> Into<(GccrsAtom, GccrsAtom)> for Pair<T1, T2>
where
GccrsAtom: From<T1> + From<T2>,

View file

@ -52,7 +52,7 @@ pub struct FactsView {
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Output {
pub loan_errors: bool,
pub subset_errors: bool,
pub move_errors: bool,
pub loan_errors: *mut FFIVector,
pub move_errors: *mut FFIVector,
pub subset_errors: *mut FFIVector,
}

View file

@ -16,13 +16,30 @@
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
mod gccrs_ffi;
mod gccrs_ffi_generated;
#![feature(extern_types)]
mod gccrs_ffi;
use gccrs_ffi::FFIVector;
use polonius_engine::{AllFacts, Atom, FactTypes, Output};
use std::fmt::Debug;
use std::hash::Hash;
extern "C" {
fn FFIVector__new() -> *mut FFIVector;
fn FFIVector__new_vec_pair() -> *mut FFIVector;
fn FFIVector__new_vec_triple() -> *mut FFIVector;
fn FFIVector__push(vector: *mut FFIVector, element: usize);
fn FFIVector__push_vec_pair(
vector: *mut FFIVector,
element: gccrs_ffi::Pair<usize, *mut FFIVector>,
);
fn FFIVector__push_vec_triple(
vector: *mut FFIVector,
element: gccrs_ffi::Triple<usize, usize, usize>,
);
}
/// A single fact value.
/// For simplicity we use one type for all facts.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
@ -46,6 +63,12 @@ impl From<GccrsAtom> for usize {
}
}
impl From<&GccrsAtom> for usize {
fn from(atom: &GccrsAtom) -> Self {
atom.index()
}
}
#[derive(Debug, Clone, Copy, Default)]
struct GccrsFacts;
@ -172,9 +195,54 @@ pub unsafe extern "C" fn polonius_run(
}
}
let loan_errors = FFIVector__new_vec_pair();
for (keys, values) in output.errors.iter() {
let loans_vec = FFIVector__new();
for loan in values.iter() {
let loan: usize = loan.into();
FFIVector__push(loans_vec, loan);
}
let point: usize = keys.into();
let pair = gccrs_ffi::Pair {
first: point,
second: loans_vec,
};
FFIVector__push_vec_pair(loan_errors, pair);
}
let move_errors = FFIVector__new_vec_pair();
for (keys, values) in output.move_errors.iter() {
let paths_vec = FFIVector__new();
for path in values.iter() {
let path: usize = path.into();
FFIVector__push(paths_vec, path);
}
let point: usize = keys.into();
let pair = gccrs_ffi::Pair {
first: point,
second: paths_vec,
};
FFIVector__push_vec_pair(move_errors, pair);
}
let subset_errors = FFIVector__new_vec_triple();
for (key, value) in output.subset_errors.iter() {
let point: usize = key.into();
for origin_pair in value.iter() {
let origin_1: usize = origin_pair.0.into();
let origin_2: usize = origin_pair.1.into();
let triple = gccrs_ffi::Triple {
first: point,
second: origin_1,
third: origin_2,
};
FFIVector__push_vec_triple(subset_errors, triple);
}
}
return gccrs_ffi::Output {
loan_errors: output.errors.len() > 0,
subset_errors: output.subset_errors.len() > 0,
move_errors: output.move_errors.len() > 0,
loan_errors,
move_errors,
subset_errors,
};
}

View file

@ -102,11 +102,76 @@ struct FactsView
Slice<Pair<Origin, Loan>> placeholder;
};
// Wrapper around std::vector to pass data from Rust to C++
template <typename T> struct FFIVector
{
std::vector<T> data;
public:
void push (T new_element) { data.push_back (new_element); };
// allocates memory to a new instance and returns the pointer
static FFIVector *make_new () { return new FFIVector{}; }
// returns current size
size_t size () const { return data.size (); }
T at (size_t index) const
{
rust_assert (index < data.size ());
return data.at (index);
}
};
// Some useful type aliases
using FFIVectorPair = FFIVector<Pair<size_t, FFIVector<size_t> *>>;
using FFIVectorTriple = FFIVector<Triple<size_t, size_t, size_t>>;
inline std::vector<size_t>
make_vector (const FFIVector<size_t> *vec_sizet)
{
std::vector<size_t> return_val (vec_sizet->size ());
for (size_t i = 0; i < vec_sizet->size (); ++i)
{
return_val[i] = vec_sizet->at (i);
}
return return_val;
}
inline std::vector<std::pair<size_t, std::vector<size_t>>>
make_vector (const FFIVectorPair *vec_pair)
{
std::vector<std::pair<size_t, std::vector<size_t>>> return_val (
vec_pair->size ());
for (size_t i = 0; i < vec_pair->size (); ++i)
{
std::pair<size_t, std::vector<size_t>> current_pair
= {vec_pair->at (i).first, make_vector (vec_pair->at (i).second)};
return_val[i] = current_pair;
}
return return_val;
}
inline std::vector<std::pair<size_t, std::pair<size_t, size_t>>>
make_vector (const FFIVectorTriple *vec_triple)
{
std::vector<std::pair<size_t, std::pair<size_t, size_t>>> return_val (
vec_triple->size ());
for (size_t i = 0; i < vec_triple->size (); ++i)
{
auto current_element = std::pair<size_t, std::pair<size_t, size_t>>{
vec_triple->at (i).first,
{vec_triple->at (i).second, vec_triple->at (i).third}};
return_val[i] = current_element;
}
return return_val;
}
struct Output
{
bool loan_errors;
bool subset_errors;
bool move_errors;
FFIVectorPair *loan_errors;
FFIVectorPair *move_errors;
FFIVectorTriple *subset_errors;
};
} // namespace FFI

View file

@ -0,0 +1,66 @@
// Copyright (C) 2020-2024 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
#include "rust-polonius.h"
namespace Rust {
namespace Polonius {
extern "C" {
FFI::FFIVector<size_t> *
FFIVector__new ()
{
return FFI::FFIVector<size_t>::make_new ();
}
FFI::FFIVectorPair *
FFIVector__new_vec_pair ()
{
return FFI::FFIVectorPair::make_new ();
}
FFI::FFIVectorTriple *
FFIVector__new_vec_triple ()
{
return FFI::FFIVectorTriple::make_new ();
}
void
FFIVector__push (FFI::FFIVector<size_t> *vector, size_t element)
{
vector->push (element);
}
void
FFIVector__push_vec_pair (FFI::FFIVectorPair *vector,
FFI::Pair<size_t, FFI::FFIVector<size_t> *> element)
{
vector->push (element);
}
void
FFIVector__push_vec_triple (FFI::FFIVectorTriple *vector,
FFI::Triple<size_t, size_t, size_t> element)
{
vector->push (element);
}
}
} // namespace Polonius
} // namespace Rust

View file

@ -225,6 +225,30 @@ struct Facts
extern "C" FFI::Output
polonius_run (FFI::FactsView input, bool dump_enabled);
// Helper functions for FFIVector to be used on Rust side
extern "C" {
FFI::FFIVector<size_t> *
FFIVector__new ();
FFI::FFIVectorPair *
FFIVector__new_vec_pair ();
FFI::FFIVectorTriple *
FFIVector__new_vec_triple ();
void
FFIVector__push (FFI::FFIVector<size_t> *vector, size_t element);
void
FFIVector__push_vec_pair (FFI::FFIVectorPair *vector,
FFI::Pair<size_t, FFI::FFIVector<size_t> *> element);
void
FFIVector__push_vec_triple (FFI::FFIVectorTriple *vector,
FFI::Triple<size_t, size_t, size_t> element);
}
} // namespace Polonius
} // namespace Rust

View file

@ -142,19 +142,29 @@ BorrowChecker::go (HIR::Crate &crate)
auto result
= Polonius::polonius_run (facts.freeze (), rust_be_debug_p ());
if (result.loan_errors)
// convert to std::vector variation for easier navigation
auto loan_errors = make_vector (result.loan_errors);
auto move_errors = make_vector (result.move_errors);
auto subset_errors = make_vector (result.subset_errors);
// free allocated data
delete result.loan_errors;
delete result.move_errors;
delete result.subset_errors;
if (!loan_errors.empty ())
{
rust_error_at (func->get_locus (), "Found loan errors in function %s",
func->get_function_name ().as_string ().c_str ());
}
if (result.subset_errors)
if (!subset_errors.empty ())
{
rust_error_at (func->get_locus (),
"Found subset errors in function %s. Some lifetime "
"constraints need to be added.",
func->get_function_name ().as_string ().c_str ());
}
if (result.move_errors)
if (!move_errors.empty ())
{
rust_error_at (func->get_locus (), "Found move errors in function %s",
func->get_function_name ().as_string ().c_str ());