diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index facdd43fd518..13745c184762 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -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. @@ -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 "$(host)" | 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. @@ -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 @@ -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 \ No newline at end of file diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/Cargo.toml b/gcc/rust/checks/errors/borrowck/ffi-polonius/Cargo.toml new file mode 100644 index 000000000000..71315c3b635e --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/Cargo.toml @@ -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" \ No newline at end of file diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/src/gccrs_ffi.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/src/gccrs_ffi.rs new file mode 100644 index 000000000000..4720150f8b03 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/src/gccrs_ffi.rs @@ -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 +// . + +// 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 { + pub first: T1, + pub second: T2, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Triple { + pub first: T1, + pub second: T2, + pub third: T3, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Slice { + pub len: u64, + pub data: *const T, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct FactsView { + pub loan_issued_at: Slice>, + pub universal_region: Slice, + pub cfg_edge: Slice>, + pub loan_killed_at: Slice>, + pub subset_base: Slice>, + pub loan_invalidated_at: Slice>, + pub var_used_at: Slice>, + pub var_defined_at: Slice>, + pub var_dropped_at: Slice>, + pub use_of_var_derefs_origin: Slice>, + pub drop_of_var_derefs_origin: Slice>, + pub child_path: Slice>, + pub path_is_var: Slice>, + pub path_assigned_at_base: Slice>, + pub path_moved_at_base: Slice>, + pub path_accessed_at_base: Slice>, + pub known_placeholder_subset: Slice>, + pub placeholder: Slice>, +} + +// GENERATED END ============================================================== + +impl Into<(GccrsAtom, GccrsAtom)> for Pair +where + GccrsAtom: From + From, +{ + fn into(self) -> (GccrsAtom, GccrsAtom) { + (self.first.into(), self.second.into()) + } +} + +impl Into<(GccrsAtom, GccrsAtom, GccrsAtom)> for Triple +where + GccrsAtom: From + From + From, +{ + fn into(self) -> (GccrsAtom, GccrsAtom, GccrsAtom) { + (self.first.into(), self.second.into(), self.third.into()) + } +} + +impl Into> for Slice +where + IN: Into + Copy, +{ + fn into(self) -> Vec { + let slice = unsafe { std::slice::from_raw_parts(self.data, self.len as usize) }; + slice.iter().map(|&e| e.into()).collect() + } +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/src/lib.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/src/lib.rs new file mode 100644 index 000000000000..4d3f6b6d75b1 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/src/lib.rs @@ -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 +// . + +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 for GccrsAtom { + fn from(inner: usize) -> GccrsAtom { + GccrsAtom(inner) + } +} + +impl From 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 for AllFacts { + fn from(input: gccrs_ffi::FactsView) -> Self { + AllFacts:: { + 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::::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); +} diff --git a/gcc/rust/checks/errors/borrowck/polonius/rust-polonius-ffi.h b/gcc/rust/checks/errors/borrowck/polonius/rust-polonius-ffi.h new file mode 100644 index 000000000000..75635804ccb8 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/polonius/rust-polonius-ffi.h @@ -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 +// . + +#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 + +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 struct Pair +{ + T1 first; + T2 second; + + Pair (T1 first, T2 second) : first (first), second (second) {} +}; + +template struct Triple +{ + T1 first; + T2 second; + T3 third; + + Triple (T1 first, T2 second, T3 third) + : first (first), second (second), third (third) + {} +}; + +template struct Slice +{ + uint64_t len; + const T *const data; + + template + Slice (const vector &v) : len (v.size ()), data (v.data ()) + {} +}; + +struct FactsView +{ + Slice> loan_issued_at; + Slice universal_region; + Slice> cfg_edge; + Slice> loan_killed_at; + Slice> subset_base; + Slice> loan_invalidated_at; + Slice> var_used_at; + Slice> var_defined_at; + Slice> var_dropped_at; + Slice> use_of_var_derefs_origin; + Slice> drop_of_var_derefs_origin; + Slice> child_path; + Slice> path_is_var; + Slice> path_assigned_at_base; + Slice> path_moved_at_base; + Slice> path_accessed_at_base; + Slice> known_placeholder_subset; + Slice> placeholder; +}; + +} // namespace FFI +} // namespace Polonius +} // namespace Rust + +#endif // RUST_POLONIUS_FACTS_FFI_H diff --git a/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h b/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h new file mode 100644 index 000000000000..9959aeb99b61 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h @@ -0,0 +1,92 @@ +// 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 +// . + +#ifndef RUST_POLONIUS_H +#define RUST_POLONIUS_H + +// Interface to the Polonius borrow checker engine. +// See (https://github.com/rust-lang/polonius/blob/master/polonius-engine/) + +#include "rust-polonius-ffi.h" + +namespace Rust { +namespace Polonius { + +struct Facts +{ + // See (https://rust-lang.github.io/polonius/rules/relations.html) + std::vector> loan_issued_at; + std::vector universal_region; + std::vector> cfg_edge; + std::vector> loan_killed_at; + std::vector> subset_base; + std::vector> loan_invalidated_at; + std::vector> var_used_at; + std::vector> var_defined_at; + std::vector> var_dropped_at; + std::vector> use_of_var_derefs_origin; + std::vector> drop_of_var_derefs_origin; + std::vector> child_path; + std::vector> path_is_var; + std::vector> path_assigned_at_base; + std::vector> path_moved_at_base; + std::vector> path_accessed_at_base; + std::vector> known_placeholder_subset; + std::vector> placeholder; + + /** + * Create a const view for the struct for FFI. + * + * This view uses the original vector storage. + * Therefore any resizing operation of Facts member may invalidate the view. + */ + FFI::FactsView freeze () + { + return FFI::FactsView{loan_issued_at, + universal_region, + cfg_edge, + loan_killed_at, + subset_base, + loan_invalidated_at, + var_used_at, + var_defined_at, + var_dropped_at, + use_of_var_derefs_origin, + drop_of_var_derefs_origin, + child_path, + path_is_var, + path_assigned_at_base, + path_moved_at_base, + path_accessed_at_base, + known_placeholder_subset, + placeholder}; + } +}; + +/** + * Check a single function for borrow errors. + * + * Output is not yet implemented and is only dumped to stdout. + */ +extern "C" void +polonius_run (FFI::FactsView input, bool dump_enabled); + +} // namespace Polonius +} // namespace Rust + +#endif /* !RUST_POLONIUS_H */ diff --git a/gcc/rust/checks/errors/borrowck/rust-borrow-checker.cc b/gcc/rust/checks/errors/borrowck/rust-borrow-checker.cc index 0c952ad32fa5..9a1865f3a252 100644 --- a/gcc/rust/checks/errors/borrowck/rust-borrow-checker.cc +++ b/gcc/rust/checks/errors/borrowck/rust-borrow-checker.cc @@ -20,6 +20,7 @@ #include "rust-function-collector.h" #include "rust-bir-builder.h" #include "rust-bir-dump.h" +#include "polonius/rust-polonius.h" namespace Rust { namespace HIR { @@ -86,6 +87,9 @@ BorrowChecker::go (HIR::Crate &crate) dump_function_bir (filename, bir, func->get_function_name ().as_string ()); } + + Polonius::Facts facts; // Dummy facts for now. + Polonius::polonius_run (facts.freeze (), true); } for (auto closure ATTRIBUTE_UNUSED : collector.get_closures ())