Merge pull request 370 from adetaylor/allow-namespace-override
diff --git a/gen/build/src/lib.rs b/gen/build/src/lib.rs
index e6de985..3e37143 100644
--- a/gen/build/src/lib.rs
+++ b/gen/build/src/lib.rs
@@ -271,7 +271,10 @@
 }
 
 fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) -> Result<()> {
-    let opt = Opt::default();
+    let opt = Opt {
+        allow_dot_includes: false,
+        ..Opt::default()
+    };
     let generated = gen::generate_from_path(rust_source_file, &opt);
     let ref rel_path = paths::local_relative_path(rust_source_file);
 
diff --git a/gen/cmd/src/app.rs b/gen/cmd/src/app.rs
index bd3bcfd..e2945a1 100644
--- a/gen/cmd/src/app.rs
+++ b/gen/cmd/src/app.rs
@@ -3,6 +3,8 @@
 mod test;
 
 use super::{Opt, Output};
+use crate::gen::include::Include;
+use crate::syntax::IncludeKind;
 use clap::AppSettings;
 use std::ffi::{OsStr, OsString};
 use std::path::PathBuf;
@@ -63,7 +65,19 @@
     let include = matches
         .values_of(INCLUDE)
         .unwrap_or_default()
-        .map(str::to_owned)
+        .map(|include| {
+            if include.starts_with('<') && include.ends_with('>') {
+                Include {
+                    path: include[1..include.len() - 1].to_owned(),
+                    kind: IncludeKind::Bracketed,
+                }
+            } else {
+                Include {
+                    path: include.to_owned(),
+                    kind: IncludeKind::Quoted,
+                }
+            }
+        })
         .collect();
 
     let mut outputs = Vec::new();
diff --git a/gen/cmd/src/main.rs b/gen/cmd/src/main.rs
index f0fd9b4..c723039 100644
--- a/gen/cmd/src/main.rs
+++ b/gen/cmd/src/main.rs
@@ -13,7 +13,8 @@
 mod syntax;
 
 use crate::gen::error::{report, Result};
-use crate::gen::{fs, include};
+use crate::gen::fs;
+use crate::gen::include::{self, Include};
 use crate::output::Output;
 use std::io::{self, Write};
 use std::path::PathBuf;
@@ -24,7 +25,7 @@
     input: Option<PathBuf>,
     header: bool,
     cxx_impl_annotations: Option<String>,
-    include: Vec<String>,
+    include: Vec<Include>,
     outputs: Vec<Output>,
 }
 
@@ -65,6 +66,7 @@
         cxx_impl_annotations: opt.cxx_impl_annotations,
         gen_header,
         gen_implementation,
+        ..Default::default()
     };
 
     let generated_code = if let Some(input) = opt.input {
diff --git a/gen/lib/src/lib.rs b/gen/lib/src/lib.rs
index ecfa436..963e870 100644
--- a/gen/lib/src/lib.rs
+++ b/gen/lib/src/lib.rs
@@ -20,8 +20,9 @@
 mod syntax;
 
 pub use crate::error::Error;
-pub use crate::gen::include::HEADER;
+pub use crate::gen::include::{Include, HEADER};
 pub use crate::gen::{GeneratedCode, Opt};
+pub use crate::syntax::IncludeKind;
 use proc_macro2::TokenStream;
 
 /// Generate C++ bindings code from a Rust token stream. This should be a Rust
diff --git a/gen/src/check.rs b/gen/src/check.rs
new file mode 100644
index 0000000..35929ad
--- /dev/null
+++ b/gen/src/check.rs
@@ -0,0 +1,27 @@
+use crate::gen::Opt;
+use crate::syntax::report::Errors;
+use crate::syntax::{error, Api};
+use quote::{quote, quote_spanned};
+use std::path::{Component, Path};
+
+pub(super) use crate::syntax::check::typecheck;
+
+pub(super) fn precheck(cx: &mut Errors, apis: &[Api], opt: &Opt) {
+    if !opt.allow_dot_includes {
+        check_dot_includes(cx, apis);
+    }
+}
+
+fn check_dot_includes(cx: &mut Errors, apis: &[Api]) {
+    for api in apis {
+        if let Api::Include(include) = api {
+            let first_component = Path::new(&include.path).components().next();
+            if let Some(Component::CurDir) | Some(Component::ParentDir) = first_component {
+                let begin = quote_spanned!(include.begin_span=> .);
+                let end = quote_spanned!(include.end_span=> .);
+                let span = quote!(#begin #end);
+                cx.error(span, error::DOT_INCLUDE.msg);
+            }
+        }
+    }
+}
diff --git a/gen/src/include.rs b/gen/src/include.rs
index 3255902..309d8c3 100644
--- a/gen/src/include.rs
+++ b/gen/src/include.rs
@@ -1,4 +1,5 @@
 use crate::gen::out::OutFile;
+use crate::syntax::{self, IncludeKind};
 use std::fmt::{self, Display};
 
 /// The complete contents of the "rust/cxx.h" header.
@@ -48,9 +49,22 @@
     }
 }
 
+/// A header to #include.
+///
+/// The cxxbridge tool does not parse or even require the given paths to exist;
+/// they simply go into the generated C++ code as #include lines.
+#[derive(Clone, PartialEq, Debug)]
+pub struct Include {
+    /// The header's path, not including the enclosing quotation marks or angle
+    /// brackets.
+    pub path: String,
+    /// Whether to emit `#include "path"` or `#include <path>`.
+    pub kind: IncludeKind,
+}
+
 #[derive(Default, PartialEq)]
 pub struct Includes {
-    custom: Vec<String>,
+    custom: Vec<Include>,
     pub array: bool,
     pub cstddef: bool,
     pub cstdint: bool,
@@ -70,24 +84,36 @@
         Includes::default()
     }
 
-    pub fn insert(&mut self, include: impl AsRef<str>) {
-        self.custom.push(include.as_ref().to_owned());
+    pub fn insert(&mut self, include: impl Into<Include>) {
+        self.custom.push(include.into());
     }
 }
 
-impl Extend<String> for Includes {
-    fn extend<I: IntoIterator<Item = String>>(&mut self, iter: I) {
-        self.custom.extend(iter);
+impl<'a> Extend<&'a Include> for Includes {
+    fn extend<I: IntoIterator<Item = &'a Include>>(&mut self, iter: I) {
+        self.custom.extend(iter.into_iter().cloned());
+    }
+}
+
+impl<'a> From<&'a syntax::Include> for Include {
+    fn from(include: &syntax::Include) -> Self {
+        Include {
+            path: include.path.clone(),
+            kind: include.kind,
+        }
     }
 }
 
 impl Display for Includes {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         for include in &self.custom {
-            if include.starts_with('<') && include.ends_with('>') {
-                writeln!(f, "#include {}", include)?;
-            } else {
-                writeln!(f, "#include \"{}\"", include.escape_default())?;
+            match include.kind {
+                IncludeKind::Quoted => {
+                    writeln!(f, "#include \"{}\"", include.path.escape_default())?;
+                }
+                IncludeKind::Bracketed => {
+                    writeln!(f, "#include <{}>", include.path)?;
+                }
             }
         }
         if self.array {
diff --git a/gen/src/mod.rs b/gen/src/mod.rs
index 92e8ec8..e6e2c7c 100644
--- a/gen/src/mod.rs
+++ b/gen/src/mod.rs
@@ -1,6 +1,7 @@
 // Functionality that is shared between the cxx_build::bridge entry point and
 // the cxxbridge CLI command.
 
+mod check;
 pub(super) mod error;
 mod file;
 pub(super) mod fs;
@@ -12,8 +13,9 @@
 pub(super) use self::error::Error;
 use self::error::{format_err, Result};
 use self::file::File;
+use self::include::Include;
 use crate::syntax::report::Errors;
-use crate::syntax::{self, check, Types};
+use crate::syntax::{self, Types};
 use std::path::Path;
 
 /// Options for C++ code generation.
@@ -35,7 +37,7 @@
     /// Any additional headers to #include. The cxxbridge tool does not parse or
     /// even require the given paths to exist; they simply go into the generated
     /// C++ code as #include lines.
-    pub include: Vec<String>,
+    pub include: Vec<Include>,
     /// Optional annotation for implementations of C++ function wrappers that
     /// may be exposed to Rust. You may for example need to provide
     /// `__declspec(dllexport)` or `__attribute__((visibility("default")))` if
@@ -45,6 +47,7 @@
 
     pub(super) gen_header: bool,
     pub(super) gen_implementation: bool,
+    pub(super) allow_dot_includes: bool,
 }
 
 /// Results of code generation.
@@ -63,6 +66,7 @@
             cxx_impl_annotations: None,
             gen_header: true,
             gen_implementation: true,
+            allow_dot_includes: true,
         }
     }
 }
@@ -112,6 +116,7 @@
     let trusted = bridge.unsafety.is_some();
     let ref apis = syntax::parse_items(errors, bridge.content, trusted, namespace);
     let ref types = Types::collect(errors, apis);
+    check::precheck(errors, apis, opt);
     errors.propagate()?;
     check::typecheck(errors, apis, types);
     errors.propagate()?;
diff --git a/gen/src/write.rs b/gen/src/write.rs
index 2ff5b47..967d4ff 100644
--- a/gen/src/write.rs
+++ b/gen/src/write.rs
@@ -18,7 +18,7 @@
         writeln!(out.front, "#pragma once");
     }
 
-    out.include.extend(opt.include.clone());
+    out.include.extend(&opt.include);
     for api in apis {
         if let Api::Include(include) = api {
             out.include.insert(include);
diff --git a/syntax/check.rs b/syntax/check.rs
index 9aba9ac..08e0dfa 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -64,7 +64,8 @@
         && !cx.types.cxx.contains(ident)
         && !cx.types.rust.contains(ident)
     {
-        cx.error(ident, &format!("unsupported type: {}", ident.to_string()));
+        let msg = format!("unsupported type: {}", ident);
+        cx.error(ident, &msg);
     }
 }
 
diff --git a/syntax/error.rs b/syntax/error.rs
index a60b7da..d0ae021 100644
--- a/syntax/error.rs
+++ b/syntax/error.rs
@@ -19,8 +19,10 @@
     CXX_STRING_BY_VALUE,
     CXX_TYPE_BY_VALUE,
     DISCRIMINANT_OVERFLOW,
+    DOT_INCLUDE,
     DOUBLE_UNDERSCORE,
     RUST_TYPE_BY_VALUE,
+    UNSUPPORTED_TYPE,
     USE_NOT_ALLOWED,
 ];
 
@@ -54,6 +56,12 @@
     note: Some("note: explicitly set `= 0` if that is desired outcome"),
 };
 
+pub static DOT_INCLUDE: Error = Error {
+    msg: "#include relative to `.` or `..` is not supported in Cargo builds",
+    label: Some("#include relative to `.` or `..` is not supported in Cargo builds"),
+    note: Some("note: use a path starting with the crate name"),
+};
+
 pub static DOUBLE_UNDERSCORE: Error = Error {
     msg: "identifiers containing double underscore are reserved in C++",
     label: Some("reserved identifier"),
@@ -66,6 +74,12 @@
     note: Some("hint: wrap it in a Box<>"),
 };
 
+pub static UNSUPPORTED_TYPE: Error = Error {
+    msg: "unsupported type: ",
+    label: Some("unsupported type"),
+    note: None,
+};
+
 pub static USE_NOT_ALLOWED: Error = Error {
     msg: "`use` items are not allowed within cxx bridge",
     label: Some("not allowed"),
diff --git a/syntax/impls.rs b/syntax/impls.rs
index a83ce74..424ad9d 100644
--- a/syntax/impls.rs
+++ b/syntax/impls.rs
@@ -1,6 +1,6 @@
 use crate::syntax::{
-    Api, CppName, ExternFn, Impl, Namespace, Pair, Receiver, Ref, ResolvableName, Signature, Slice,
-    Symbol, Ty1, Type, Types,
+    Api, CppName, ExternFn, Impl, Include, Namespace, Pair, Receiver, Ref, ResolvableName,
+    Signature, Slice, Symbol, Ty1, Type, Types,
 };
 use proc_macro2::{Ident, Span};
 use std::borrow::Borrow;
@@ -9,6 +9,24 @@
 use std::ops::{Deref, DerefMut};
 use syn::Token;
 
+impl PartialEq for Include {
+    fn eq(&self, other: &Include) -> bool {
+        let Include {
+            path,
+            kind,
+            begin_span: _,
+            end_span: _,
+        } = self;
+        let Include {
+            path: path2,
+            kind: kind2,
+            begin_span: _,
+            end_span: _,
+        } = other;
+        path == path2 && kind == kind2
+    }
+}
+
 impl Deref for ExternFn {
     type Target = Signature;
 
diff --git a/syntax/mod.rs b/syntax/mod.rs
index bb9566d..6498d74 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -59,7 +59,7 @@
 }
 
 pub enum Api {
-    Include(String),
+    Include(Include),
     Struct(Struct),
     Enum(Enum),
     CxxType(ExternType),
@@ -70,6 +70,22 @@
     Impl(Impl),
 }
 
+pub struct Include {
+    pub path: String,
+    pub kind: IncludeKind,
+    pub begin_span: Span,
+    pub end_span: Span,
+}
+
+/// Whether to emit `#include "path"` or `#include <path>`.
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum IncludeKind {
+    /// `#include "quoted/path/to"`
+    Quoted,
+    /// `#include <bracketed/path/to>`
+    Bracketed,
+}
+
 pub struct ExternType {
     pub doc: Doc,
     pub type_token: Token![type],
diff --git a/syntax/parse.rs b/syntax/parse.rs
index 0a86b6c..7a56ab8 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -3,8 +3,9 @@
 use crate::syntax::report::Errors;
 use crate::syntax::Atom::*;
 use crate::syntax::{
-    attrs, error, Api, CppName, Doc, Enum, ExternFn, ExternType, Impl, Lang, Namespace, Pair,
-    Receiver, Ref, ResolvableName, Signature, Slice, Struct, Ty1, Type, TypeAlias, Var, Variant,
+    attrs, error, Api, CppName, Doc, Enum, ExternFn, ExternType, Impl, Include, IncludeKind, Lang,
+    Namespace, Pair, Receiver, Ref, ResolvableName, Signature, Slice, Struct, Ty1, Type, TypeAlias,
+    Var, Variant,
 };
 use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
 use quote::{format_ident, quote, quote_spanned};
@@ -510,15 +511,22 @@
     }))
 }
 
-fn parse_include(input: ParseStream) -> Result<String> {
+fn parse_include(input: ParseStream) -> Result<Include> {
     if input.peek(LitStr) {
-        return Ok(input.parse::<LitStr>()?.value());
+        let lit: LitStr = input.parse()?;
+        let span = lit.span();
+        return Ok(Include {
+            path: lit.value(),
+            kind: IncludeKind::Quoted,
+            begin_span: span,
+            end_span: span,
+        });
     }
 
     if input.peek(Token![<]) {
         let mut path = String::new();
-        input.parse::<Token![<]>()?;
-        path.push('<');
+
+        let langle: Token![<] = input.parse()?;
         while !input.is_empty() && !input.peek(Token![>]) {
             let token: TokenTree = input.parse()?;
             match token {
@@ -534,9 +542,14 @@
                 _ => return Err(Error::new(token.span(), "unexpected token in include path")),
             }
         }
-        input.parse::<Token![>]>()?;
-        path.push('>');
-        return Ok(path);
+        let rangle: Token![>] = input.parse()?;
+
+        return Ok(Include {
+            path,
+            kind: IncludeKind::Bracketed,
+            begin_span: langle.span,
+            end_span: rangle.span,
+        });
     }
 
     Err(input.error("expected \"quoted/path/to\" or <bracketed/path/to>"))