diff --git a/README.md b/README.md
index 208aa550882..50c2bd95b7f 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,7 @@ We have a bunch of lint categories to allow you to choose how much clippy is sup
 * `clippy_style` (code that should be written in a more idiomatic way)
 * `clippy_complexity` (code that does something simple but in a complex way)
 * `clippy_perf` (code that can be written in a faster way)
+* `clippy_cargo` (checks against the cargo manifest)
 * **`clippy_correctness`** (code that is just outright wrong or very very useless)
 
 More to come, please [file an issue](https://github.com/rust-lang-nursery/rust-clippy/issues) if you have ideas!
diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml
index 17c1c25669f..e17aa75cdf5 100644
--- a/clippy_lints/Cargo.toml
+++ b/clippy_lints/Cargo.toml
@@ -16,6 +16,7 @@ license = "MPL-2.0"
 keywords = ["clippy", "lint", "plugin"]
 
 [dependencies]
+cargo_metadata = "0.5"
 itertools = "0.7"
 lazy_static = "1.0"
 matches = "0.1.2"
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index a952f5081f4..0a500f9ad6e 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -16,6 +16,7 @@
 #![feature(iterator_find_map)]
 
 
+extern crate cargo_metadata;
 #[macro_use]
 extern crate rustc;
 extern crate rustc_typeck;
@@ -81,6 +82,9 @@ macro_rules! declare_clippy_lint {
     { pub $name:tt, restriction, $description:tt } => {
         declare_lint! { pub $name, Allow, $description }
     };
+    { pub $name:tt, cargo, $description:tt } => {
+        declare_lint! { pub $name, Allow, $description }
+    };
     { pub $name:tt, nursery, $description:tt } => {
         declare_lint! { pub $name, Allow, $description }
     };
@@ -158,6 +162,7 @@ pub mod minmax;
 pub mod misc;
 pub mod misc_early;
 pub mod missing_doc;
+pub mod multiple_crate_versions;
 pub mod mut_mut;
 pub mod mut_reference;
 pub mod mutex_atomic;
@@ -412,6 +417,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
     reg.register_late_lint_pass(box question_mark::QuestionMarkPass);
     reg.register_late_lint_pass(box suspicious_trait_impl::SuspiciousImpl);
     reg.register_late_lint_pass(box redundant_field_names::RedundantFieldNames);
+    reg.register_early_lint_pass(box multiple_crate_versions::Pass);
     reg.register_late_lint_pass(box map_unit_fn::Pass);
     reg.register_late_lint_pass(box infallible_destructuring_match::Pass);
 
@@ -895,6 +901,10 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
         vec::USELESS_VEC,
     ]);
 
+    reg.register_lint_group("clippy_cargo", vec![
+        multiple_crate_versions::MULTIPLE_CRATE_VERSIONS,
+    ]);
+
     reg.register_lint_group("clippy_nursery", vec![
         attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
         fallible_impl_from::FALLIBLE_IMPL_FROM,
diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs
new file mode 100644
index 00000000000..d347270236d
--- /dev/null
+++ b/clippy_lints/src/multiple_crate_versions.rs
@@ -0,0 +1,72 @@
+//! lint on multiple versions of a crate being used
+
+use rustc::lint::*;
+use syntax::ast::*;
+
+use cargo_metadata;
+use itertools::Itertools;
+
+/// **What it does:** Checks to see if multiple versions of a crate are being
+/// used.
+///
+/// **Why is this bad?** This bloats the size of targets, and can lead to
+/// confusing error messages when structs or traits are used interchangeably
+/// between different versions of a crate.
+///
+/// **Known problems:** Because this can be caused purely by the dependencies
+/// themselves, it's not always possible to fix this issue.
+///
+/// **Example:**
+/// ```toml
+/// # This will pull in both winapi v0.3.4 and v0.2.8, triggering a warning.
+/// [dependencies]
+/// ctrlc = "3.1.0"
+/// ansi_term = "0.11.0"
+/// ```
+declare_clippy_lint! {
+    pub MULTIPLE_CRATE_VERSIONS,
+    cargo,
+    "multiple versions of the same crate being used"
+}
+
+pub struct Pass;
+
+impl LintPass for Pass {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(MULTIPLE_CRATE_VERSIONS)
+    }
+}
+
+impl EarlyLintPass for Pass {
+    fn check_crate(&mut self, cx: &EarlyContext, krate: &Crate) {
+        let metadata = match cargo_metadata::metadata_deps(None, true) {
+            Ok(metadata) => metadata,
+            Err(_) => {
+                cx.span_lint(
+                    MULTIPLE_CRATE_VERSIONS,
+                    krate.span,
+                    "could not read cargo metadata"
+                );
+
+                return;
+            }
+        };
+
+        let mut packages = metadata.packages;
+        packages.sort_by(|a, b| a.name.cmp(&b.name));
+
+        for (name, group) in &packages.into_iter().group_by(|p| p.name.clone()) {
+            let group: Vec<cargo_metadata::Package> = group.collect();
+
+            if group.len() > 1 {
+                let versions = group.into_iter().map(|p| p.version).join(", ");
+
+                cx.span_lint(
+                    MULTIPLE_CRATE_VERSIONS,
+                    krate.span,
+                    &format!("multiple versions for dependency `{}`: {}", name, versions),
+                );
+            }
+        }
+    }
+}
diff --git a/util/lintlib.py b/util/lintlib.py
index c28177e1062..4323ef5c3e7 100644
--- a/util/lintlib.py
+++ b/util/lintlib.py
@@ -24,6 +24,7 @@ lint_levels = {
     "restriction": 'Allow',
     "pedantic": 'Allow',
     "nursery": 'Allow',
+    "cargo": 'Allow',
 }
 
 
diff --git a/util/update_lints.py b/util/update_lints.py
index 58caa5dac0d..692599886a9 100755
--- a/util/update_lints.py
+++ b/util/update_lints.py
@@ -129,6 +129,7 @@ def main(print_only=False, check=False):
         "perf": [],
         "restriction": [],
         "pedantic": [],
+        "cargo": [],
         "nursery": [],
     }