Skip to content

Commit

Permalink
borrowck: Polonius FFI
Browse files Browse the repository at this point in the history
gcc/rust/ChangeLog:

	* Make-lang.in: Build FFI-Polonius.
	* checks/errors/borrowck/rust-borrow-checker.cc (BorrowChecker::go): Invoke Polonius.
	* checks/errors/borrowck/ffi-polonius/Cargo.toml: New file.
	* checks/errors/borrowck/ffi-polonius/src/gccrs_ffi.rs: New file.
	* checks/errors/borrowck/ffi-polonius/src/lib.rs: New file.
	* checks/errors/borrowck/polonius/rust-polonius-ffi.h: New file.
	* checks/errors/borrowck/polonius/rust-polonius.h: New file.

Signed-off-by: Jakub Dupak <[email protected]>
  • Loading branch information
jdupak committed Oct 31, 2023
1 parent 2ec81de commit b34dd80
Show file tree
Hide file tree
Showing 7 changed files with 432 additions and 3 deletions.
19 changes: 16 additions & 3 deletions gcc/rust/Make-lang.in
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

# This file provides the language dependent support in the main Makefile.


#RUST_EXES = rust

# Use strict warnings for this front end.
Expand Down Expand Up @@ -199,14 +200,19 @@ RUST_ALL_OBJS = $(GRS_OBJS) $(RUST_TARGET_OBJS)

rust_OBJS = $(RUST_ALL_OBJS) rust/rustspec.o

RUST_LDFLAGS = $(LDFLAGS) -L./../libgrust/libproc_macro_internal
RUST_LIBDEPS = $(LIBDEPS) ../libgrust/libproc_macro_internal/libproc_macro_internal.a
# FIXME: Experiment - move to configure
CLANG_TARGET := $(shell echo "$(target)" | sed 's/-pc-/-unknown-/')
POLONIUS_LDFLAGS = $(shell cargo rustc --manifest-path $(srcdir)/rust/checks/errors/borrowck/ffi-polonius/Cargo.toml -q --message-format short -- --target $(CLANG_TARGET) --print=native-static-libs | grep "note: native-static-libs:" | sed 's/note: native-static-libs: //g')
RUST_LDFLAGS = $(LDFLAGS) -L./../libgrust/libproc_macro_internal $(POLONIUS_LDFLAGS)
RUST_LIBDEPS = $(LIBDEPS) ../libgrust/libproc_macro_internal/libproc_macro_internal.a rust/libffi_polonius.a

# The compiler itself is called crab1
crab1$(exeext): $(RUST_ALL_OBJS) attribs.o $(BACKEND) $(RUST_LIBDEPS) $(rust.prev)
@$(call LINK_PROGRESS,$(INDEX.rust),start)
+$(LLINKER) $(ALL_LINKERFLAGS) $(RUST_LDFLAGS) -o $@ \
$(RUST_ALL_OBJS) attribs.o $(BACKEND) $(LIBS) ../libgrust/libproc_macro_internal/libproc_macro_internal.a $(BACKENDLIBS)
$(RUST_ALL_OBJS) attribs.o $(BACKEND) \
$(LIBS) ../libgrust/libproc_macro_internal/libproc_macro_internal.a rust/libffi_polonius.a \
$(BACKENDLIBS)
@$(call LINK_PROGRESS,$(INDEX.rust),end)

# Build hooks.
Expand Down Expand Up @@ -240,6 +246,7 @@ rust.srcman:
# Clean hooks.

rust.mostlyclean:
rm -rf rust/ffi-polonius/release libffi_polonius.a
# cd $(srcdir)/rust; rm -f *.o y.tab.h y.tab.c lex.yy.c

rust.clean: rust.mostlyclean
Expand Down Expand Up @@ -461,3 +468,9 @@ rust/%.o: rust/checks/errors/borrowck/%.cc
rust/%.o: rust/metadata/%.cc
$(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $<
$(POSTCOMPILE)

rust/libffi_polonius.a: \
rust/checks/errors/borrowck/ffi-polonius/Cargo.toml \
$(wildcard $(srcdir)/rust/checks/errors/borrowck/ffi-polonius/src/*)
cargo build --manifest-path $(srcdir)/rust/checks/errors/borrowck/ffi-polonius/Cargo.toml --release --target-dir rust/ffi-polonius
cp rust/ffi-polonius/release/libffi_polonius.a rust/libffi_polonius.a
11 changes: 11 additions & 0 deletions gcc/rust/checks/errors/borrowck/ffi-polonius/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "ffi-polonius"
version = "0.1.0"
edition = "2021"
license = "GPL-3"

[lib]
crate-type = ["staticlib"]

[dependencies]
polonius-engine = "0.13.0"
115 changes: 115 additions & 0 deletions gcc/rust/checks/errors/borrowck/ffi-polonius/src/gccrs_ffi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Copyright (C) 2023 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/>.

// This is an FFI interface to gccrs (c++).
// It is a counterpart to `rust-polonius-ffi.h`.

// Generated by rust-bindgen, remove unsafe phantoms and add Into impls.
// ```shell
// bindgen \
// --generate types \
// --allowlist-file rust-polonius-facts-ffi.h \
// --no-layout-tests \
// rust-polonius-ffi.h \
// -- -x c++
// ```

// GENERATED START ============================================================

use crate::GccrsAtom;

pub type Origin = usize;
pub type Loan = usize;
pub type Point = usize;
pub type Variable = usize;
pub type Path = usize;

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Pair<T1, T2> {
pub first: T1,
pub second: T2,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Triple<T1, T2, T3> {
pub first: T1,
pub second: T2,
pub third: T3,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Slice<T> {
pub len: u64,
pub data: *const T,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct FactsView {
pub loan_issued_at: Slice<Triple<Origin, Loan, Point>>,
pub universal_region: Slice<Origin>,
pub cfg_edge: Slice<Pair<Point, Point>>,
pub loan_killed_at: Slice<Pair<Loan, Point>>,
pub subset_base: Slice<Triple<Origin, Origin, Point>>,
pub loan_invalidated_at: Slice<Pair<Point, Loan>>,
pub var_used_at: Slice<Pair<Variable, Point>>,
pub var_defined_at: Slice<Pair<Variable, Point>>,
pub var_dropped_at: Slice<Pair<Variable, Point>>,
pub use_of_var_derefs_origin: Slice<Pair<Variable, Origin>>,
pub drop_of_var_derefs_origin: Slice<Pair<Variable, Origin>>,
pub child_path: Slice<Pair<Path, Path>>,
pub path_is_var: Slice<Pair<Path, Variable>>,
pub path_assigned_at_base: Slice<Pair<Path, Point>>,
pub path_moved_at_base: Slice<Pair<Path, Point>>,
pub path_accessed_at_base: Slice<Pair<Path, Point>>,
pub known_placeholder_subset: Slice<Pair<Origin, Origin>>,
pub placeholder: Slice<Pair<Origin, Loan>>,
}

// GENERATED END ==============================================================

impl<T1, T2> Into<(GccrsAtom, GccrsAtom)> for Pair<T1, T2>
where
GccrsAtom: From<T1> + From<T2>,
{
fn into(self) -> (GccrsAtom, GccrsAtom) {
(self.first.into(), self.second.into())
}
}

impl<T1, T2, T3> Into<(GccrsAtom, GccrsAtom, GccrsAtom)> for Triple<T1, T2, T3>
where
GccrsAtom: From<T1> + From<T2> + From<T3>,
{
fn into(self) -> (GccrsAtom, GccrsAtom, GccrsAtom) {
(self.first.into(), self.second.into(), self.third.into())
}
}

impl<OUT, IN> Into<Vec<OUT>> for Slice<IN>
where
IN: Into<OUT> + Copy,
{
fn into(self) -> Vec<OUT> {
let slice = unsafe { std::slice::from_raw_parts(self.data, self.len as usize) };
slice.iter().map(|&e| e.into()).collect()
}
}
96 changes: 96 additions & 0 deletions gcc/rust/checks/errors/borrowck/ffi-polonius/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright (C) 2023 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/>.

mod gccrs_ffi;

use polonius_engine::{AllFacts, Atom, FactTypes, Output};
use std::fmt::Debug;
use std::hash::Hash;

/// A single fact value.
/// For simplicity we use one type for all facts.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct GccrsAtom(usize);

impl Atom for GccrsAtom {
fn index(self) -> usize {
self.0
}
}

impl From<usize> for GccrsAtom {
fn from(inner: usize) -> GccrsAtom {
GccrsAtom(inner)
}
}

impl From<GccrsAtom> for usize {
fn from(atom: GccrsAtom) -> Self {
atom.index()
}
}

#[derive(Debug, Clone, Copy, Default)]
struct GccrsFacts;

impl FactTypes for GccrsFacts {
type Origin = GccrsAtom;
type Loan = GccrsAtom;
type Point = GccrsAtom;
type Variable = GccrsAtom;
type Path = GccrsAtom;
}

impl From<gccrs_ffi::FactsView> for AllFacts<GccrsFacts> {
fn from(input: gccrs_ffi::FactsView) -> Self {
AllFacts::<GccrsFacts> {
loan_issued_at: input.loan_issued_at.into(),
universal_region: input.universal_region.into(),
cfg_edge: input.cfg_edge.into(),
loan_killed_at: input.loan_killed_at.into(),
subset_base: input.subset_base.into(),
loan_invalidated_at: input.loan_invalidated_at.into(),
var_used_at: input.var_used_at.into(),
var_defined_at: input.var_defined_at.into(),
var_dropped_at: input.var_dropped_at.into(),
use_of_var_derefs_origin: input.use_of_var_derefs_origin.into(),
drop_of_var_derefs_origin: input.drop_of_var_derefs_origin.into(),
child_path: input.child_path.into(),
path_is_var: input.path_is_var.into(),
path_assigned_at_base: input.path_assigned_at_base.into(),
path_moved_at_base: input.path_moved_at_base.into(),
path_accessed_at_base: input.path_accessed_at_base.into(),
known_placeholder_subset: input.known_placeholder_subset.into(),
placeholder: input.placeholder.into(),
}
}
}

/// Run the polonius analysis on the given facts (for a single function).
/// Right now, results are only printed and not propagated back to the gccrs.
#[no_mangle]
pub unsafe extern "C" fn polonius_run(input: gccrs_ffi::FactsView, dump_enabled: bool) {
let facts = AllFacts::<GccrsFacts>::from(input);
let output = Output::compute(&facts, polonius_engine::Algorithm::Naive, dump_enabled);

// FIXME: Temporary output
println!("Polonius analysis completed. Results:");
println!("Errors: {:#?}", output.errors);
println!("Subset error: {:#?}", output.subset_errors);
println!("Move error: {:#?}", output.move_errors);
}
98 changes: 98 additions & 0 deletions gcc/rust/checks/errors/borrowck/polonius/rust-polonius-ffi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright (C) 2023 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/>.

#ifndef RUST_POLONIUS_FACTS_FFI_H
#define RUST_POLONIUS_FACTS_FFI_H

// This file defines the C++ side of the FFI interface to Polonius.
// The corresponding Rust side is in `gccrs-ffi.rs`.

// IMPORTANT:
// This file intentionally does not include any C++ headers
// to allow seamless binding generation on the Rust side.

#include <cstdint>

namespace Rust {
namespace Polonius {

using Origin = size_t;
using Loan = size_t;
using Point = size_t;
using Variable = size_t;
using Path = size_t;

namespace FFI {

// NOTE: std::pair and std::tuple are complicating the bindings' generation.
template <typename T1, typename T2> struct Pair
{
T1 first;
T2 second;

Pair (T1 first, T2 second) : first (first), second (second) {}
};

template <typename T1, typename T2, typename T3> struct Triple
{
T1 first;
T2 second;
T3 third;

Triple (T1 first, T2 second, T3 third)
: first (first), second (second), third (third)
{}
};

template <typename T> struct Slice
{
uint64_t len;
const T *const data;

template <typename vector>
Slice (const vector &v) : len (v.size ()), data (v.data ())
{}
};

struct FactsView
{
Slice<Triple<Origin, Loan, Point>> loan_issued_at;
Slice<Origin> universal_region;
Slice<Pair<Point, Point>> cfg_edge;
Slice<Pair<Loan, Point>> loan_killed_at;
Slice<Triple<Origin, Origin, Point>> subset_base;
Slice<Pair<Point, Loan>> loan_invalidated_at;
Slice<Pair<Variable, Point>> var_used_at;
Slice<Pair<Variable, Point>> var_defined_at;
Slice<Pair<Variable, Point>> var_dropped_at;
Slice<Pair<Variable, Origin>> use_of_var_derefs_origin;
Slice<Pair<Variable, Origin>> drop_of_var_derefs_origin;
Slice<Pair<Path, Path>> child_path;
Slice<Pair<Path, Variable>> path_is_var;
Slice<Pair<Path, Point>> path_assigned_at_base;
Slice<Pair<Path, Point>> path_moved_at_base;
Slice<Pair<Path, Point>> path_accessed_at_base;
Slice<Pair<Origin, Origin>> known_placeholder_subset;
Slice<Pair<Origin, Loan>> placeholder;
};

} // namespace FFI
} // namespace Polonius
} // namespace Rust

#endif // RUST_POLONIUS_FACTS_FFI_H
Loading

0 comments on commit b34dd80

Please sign in to comment.