diff --git a/ChangeLog b/ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+0.1.0.8:
+- Doc fixes
+- Since support for GHC < 7.4 was dropped, don't need notcpp or related code
+- Make dependency bounds more optimistic
+
 0.1.0.7:
 - Make it a little more obvious that the package is unmaintained
 
diff --git a/Control/Applicative/QQ/ADo.hs b/Control/Applicative/QQ/ADo.hs
--- a/Control/Applicative/QQ/ADo.hs
+++ b/Control/Applicative/QQ/ADo.hs
@@ -19,9 +19,6 @@
 
     -- * Desugaring
     -- $desugaring
-
-    -- * Caveats
-    -- $caveats
     ) where
 
 import Control.Applicative
@@ -29,10 +26,7 @@
 import Language.Haskell.TH
 import Language.Haskell.TH.Quote
 import Control.Monad
-import Data.Data (cast, gmapQ)
 
-import NotCPP.ScopeLookup (scopeLookup)
-
 -- $desugaring
 --
 -- If you use patterns that may fail:
@@ -68,23 +62,6 @@
 --
 -- > foo = (\ ~(x:xs) (A y) -> T x y) <$> foo bar baz <*> quux quaffle
 
--- $caveats
---
--- Prior to GHC 7.4 and Template Haskell 2.7, it was impossible to reliably
--- look up constructor names just from a string: if there is a type with the
--- same name, it will return information for that instead.
---
--- This means that the safe version of 'ado' is prone to failure where types
--- and values share names. It tries to make a \"best guess\" in the common
--- case that type and constructor have the same name, but has nontrivial
--- failure modes.
---
--- In such cases, 'ado'' should work fine: at a pinch, you
--- can bind simple variables with it and case-match on them in your last
--- statement.
---
--- See also: <http://hackage.haskell.org/trac/ghc/ticket/4429>
-
 -- | Usage:
 --
 -- > ghci> [$ado| a <- "foo"; b <- "bar"; (a,b) |]
@@ -153,72 +130,44 @@
 
 failingPattern :: Pat -> Q Bool
 failingPattern pat = case pat of
-  LitP {} -> return True
+  -- patterns that always succeed
   VarP {} -> return False
-  TupP ps -> anyFailing ps
-  ConP n ps -> liftM2 ((||) . not) (singleCon n) (anyFailing ps)
-  InfixP p n q -> failingPattern $ ConP n [p, q]
   TildeP {} -> return False
   WildP -> return False
-  RecP n fps -> failingPattern $ ConP n (map snd fps)
+  -- patterns that can fail
+  LitP {} -> return True
   ListP {} -> return True
-  -- recurse on any subpatterns
-  -- we do this implicitly because it avoids referring to the constructors
-  -- by name, which means we can work with TH versions where they didn't
-  -- exist
-  _ -> fmap or . sequence $ gmapQ (mkQ (return False) failingPattern) pat
+  -- ConP can fail if the constructor is not the only constructor of its type
+  -- /or/ if any of the subpatterns can fail
+  ConP n ps -> liftM2 (\x y -> not x || y) (singleCon n) (anyFailing ps)
+  -- some other patterns are essentially ConP patterns
+  InfixP p n q -> failingPattern $ ConP n [p, q]
+  UInfixP p n q -> failingPattern $ ConP n [p, q]
+  RecP n fps -> failingPattern $ ConP n (map snd fps)
+  -- recursive cases
+  TupP ps -> anyFailing ps
+  UnboxedTupP ps -> anyFailing ps
+  ParensP p -> failingPattern p
+  BangP p -> failingPattern p
+  AsP _ p -> failingPattern p
+  SigP p _ -> failingPattern p
+  ViewP _ p -> failingPattern p
  where
   anyFailing = fmap or . mapM failingPattern
-  mkQ d f x = maybe d f (cast x)
 
--- Uses lookupValueName when available via TH magic, otherwise tries a
--- best-guess approach (see the caveats section)
--- | Given a 'Name' of a value constructor, find the 'TyConI dec' of its
--- type, and return 'dec'
-findTyCon :: Name -> Q Dec
-findTyCon n = case $(scopeLookup "lookupValueName") of
-  Just fn -> do
-    DataConI _ _ tn _ <- maybe noScope reify =<< fn (show n)
-    TyConI dec <- reify tn
-    return dec
-   where
-    noScope = fail $ "Data constructor " ++ show n ++ " not in scope"
-  Nothing -> do
-    -- This is what we do when lookupValueName isn't available.
-    info <- reify n
-    -- This covers the common case of a data type with one of the
-    -- constructors being named the same as the type, but fails if there
-    -- is a type Foo and a constructor Foo of a different type :(
-    TyConI dec <- case info of
-        DataConI _ _ tn _ -> reify tn
-        -- we hope that the base of the tn is the same, but it is
-        -- properly qualified
-        TyConI (DataD _ _ _ cs _)
-          | any rightName cs -> return info
-          | otherwise -> errShadow
-        TyConI (NewtypeD _ _ _ c _)
-          | rightName c -> return info
-          | otherwise -> errShadow
-        _ -> fail $ "ado singleCon: not a constructor: " ++ show info
-    return dec
-   where
-    rightName c = nameBase n == nameBase (conName c)
-    errShadow = fail . concat $ ["ado singleCon: couldn't find data ",
-        "dec for name: ", show n, ", sorry :( - try using ado' instead"]
-
 -- | Take the name of a value constructor and try to find out if it is
 -- the only constructor of its type
 singleCon :: Name -> Q Bool
 singleCon n = do
-    dec <- findTyCon n
-    case dec of
-        DataD _ _ _ [_] _ -> return True
-        NewtypeD {} -> return True
-        DataD _ _ _ (_:_) _ -> return False
-        _ -> fail $ "ado singleCon: not a data declaration: " ++ show dec
-
-conName :: Con -> Name
-conName (NormalC n _) = n
-conName (RecC n _) = n
-conName (InfixC _ n _) = n
-conName (ForallC _ _ c) = conName c
+  dec <- recover noScope $ do
+    Just vn <- lookupValueName (show n)
+    DataConI _ _ tn _ <- reify vn
+    TyConI dec <- reify tn
+    return dec
+  case dec of
+    DataD _ _ _ [_] _ -> return True
+    NewtypeD {} -> return True
+    DataD _ _ _ (_:_) _ -> return False
+    _ -> fail $ "ado singleCon: not a data declaration: " ++ show dec
+ where
+  noScope = fail $ "Data constructor " ++ show n ++ " lookup failed."
diff --git a/Control/Applicative/QQ/Idiom.hs b/Control/Applicative/QQ/Idiom.hs
--- a/Control/Applicative/QQ/Idiom.hs
+++ b/Control/Applicative/QQ/Idiom.hs
@@ -11,22 +11,22 @@
 import Language.Haskell.TH.Quote
 import Language.Haskell.TH.Syntax
 
--- | Turns function application into <*>, and puts a pure on the beginning.
+-- | Turns function application into '<*>', and puts a 'pure' on the beginning.
 --
--- [i| subtract [1,2,3] [10,20,30] |]
--- -> pure subtract <*> [1,2,3] <*> [10,20,30]
--- -> [99,199,299,98,198,298,97,197,297]
+-- > [i| subtract [1,2,3] [10,20,30] |]
+-- > -> pure subtract <*> [1,2,3] <*> [10,20,30]
+-- > -> [9,19,29,8,18,28,7,17,27]
 --
 -- Does not apply to nested applications:
 --
--- getZipList [i| subtract (ZipList [1,2,3]) (ZipList [100,200,300]) |]
--- -> getZipList (pure subtract <*> ZipList [1,2,3] <*> ZipList [100,200,300])
--- -> [99,198,297]
+-- > getZipList [i| subtract (ZipList [1,2,3]) (ZipList [10,20,30]) |]
+-- > -> getZipList (pure subtract <*> ZipList [1,2,3] <*> ZipList [10,20,30])
+-- > -> [9,18,27]
 --
--- Will treat [i| x `op` y |] as [i| op x y |] as long as neither x nor y
--- are an infix expression. The precise behaviour when x or y are infix
--- applications depends on what haskell-src-meta does, which depends on what
--- TH supports, so may depend on your GHC version.
+-- Will treat @[i| x \`op\` y |]@ as @[i| op x y |]@ as long as neither x nor y
+-- are an infix expression. If they are, will likely complain that it doesn't
+-- have fixity information (unless haskell-src-meta becomes clever enough to
+-- resolve that itself).
 i :: QuasiQuoter
 i = QuasiQuoter { quoteExp = applicate <=< either fail return . parseExp,
   quotePat = nonsense "pattern",
diff --git a/applicative-quoters.cabal b/applicative-quoters.cabal
--- a/applicative-quoters.cabal
+++ b/applicative-quoters.cabal
@@ -1,7 +1,7 @@
 Cabal-Version: >= 1.6
 
 Name:     applicative-quoters
-Version:  0.1.0.7
+Version:  0.1.0.8
 Category: Language
 Synopsis: Quasiquoters for idiom brackets and an applicative do-notation
 
@@ -29,10 +29,9 @@
       Control.Applicative.QQ.Idiom
 
   Build-depends:
-      base >= 4 && < 4.7,
-      haskell-src-meta >= 0.2 && < 0.7,
-      notcpp < 0.3,
-      template-haskell >= 2.7 && < 2.9
+      base >= 4 && < 5,
+      haskell-src-meta >= 0.2 && < 1,
+      template-haskell >= 2.7 && < 3
 
   Extensions:
       TemplateHaskell
