diff --git a/core/lib/Drupal/Core/Routing/RouteProvider.php b/core/lib/Drupal/Core/Routing/RouteProvider.php
index da9dc1b..0011bdd 100644
--- a/core/lib/Drupal/Core/Routing/RouteProvider.php
+++ b/core/lib/Drupal/Core/Routing/RouteProvider.php
@@ -259,23 +259,27 @@ public function getCandidateOutlines(array $parts) {
   /**
    * {@inheritdoc}
    */
-  public function getRoutesByPattern($pattern) {
-    $path = RouteCompiler::getPatternOutline($pattern);
+  public function getRoutesByExactPattern($pattern) {
+    $outline = RouteCompiler::getPatternOutline($pattern);
     $this->routeBuilder->rebuildIfNeeded();
 
-    return $this->getRoutesByPath($path);
+    $routes = $this->connection->query("SELECT name, route FROM {" . $this->connection->escapeTable($this->tableName) . "} WHERE pattern_outline = :outline ORDER BY fit DESC", array(
+      ':outline' => $outline,
+    ))
+      ->fetchAllKeyed();
+    $collection = new RouteCollection();
+    foreach ($routes as $name => $route) {
+      $route = unserialize($route);
+      $collection->add($name, $route);
+    }
+
+    return $collection;
   }
 
   /**
-   * Get all routes which match a certain pattern.
-   *
-   * @param string $path
-   *   The route pattern to search for (contains % as placeholders).
-   *
-   * @return \Symfony\Component\Routing\RouteCollection
-   *   Returns a route collection of matching routes.
+   * {@inheritdoc}
    */
-  protected function getRoutesByPath($path) {
+  public function getRoutesByPath($path) {
     // Filter out each empty value, though allow '0' and 0, which would be
     // filtered out by empty().
     $parts = array_values(array_filter(explode('/', $path), function($value) {
diff --git a/core/lib/Drupal/Core/Routing/RouteProviderInterface.php b/core/lib/Drupal/Core/Routing/RouteProviderInterface.php
index 8c8e356..a893e5d 100644
--- a/core/lib/Drupal/Core/Routing/RouteProviderInterface.php
+++ b/core/lib/Drupal/Core/Routing/RouteProviderInterface.php
@@ -18,7 +18,10 @@
 interface RouteProviderInterface extends RouteProviderBaseInterface {
 
   /**
-   * Get all routes which match a certain pattern.
+   * Get all routes which match exactly the given pattern.
+   *
+   * This method does not return something if you do specify actual values
+   * for placeholders.
    *
    * @param string $pattern
    *   The route pattern to search for (contains {} as placeholders).
@@ -26,7 +29,21 @@
    * @return \Symfony\Component\Routing\RouteCollection
    *   Returns a route collection of matching routes.
    */
-  public function getRoutesByPattern($pattern);
+  public function getRoutesByExactPattern($pattern);
+
+  /**
+   * Get all routes which match a certain path.
+   *
+   * This method does return something if you specify values for the
+   * placeholders.
+   *
+   * @param string $path
+   *   The route path to match (a concrete path with no placeholders).
+   *
+   * @return \Symfony\Component\Routing\RouteCollection
+   *   Returns a route collection of matching routes.
+   */
+  public function getRoutesByPath($path);
 
   /**
    * Returns all the routes on the system.
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index 88c64dd..f0ec3f0 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -235,6 +235,29 @@ function shortcut_set_title_exists($title) {
 }
 
 /**
+ * Determines if a path corresponds to a valid shortcut link.
+ *
+ * @param string $path
+ *   The path to the link.
+ *
+ * @return bool
+ *   TRUE if the shortcut link is valid, FALSE otherwise. Valid links are ones
+ *   that correspond to actual paths on the site.
+ *
+ * @see menu_edit_item_validate()
+ */
+function shortcut_valid_link($path) {
+  // Do not use URL aliases.
+  $normal_path = \Drupal::service('path.alias_manager')->getSystemPath($path);
+  if ($path != $normal_path) {
+    $path = $normal_path;
+  }
+
+  // An empty path is valid too and will be converted to <front>.
+  return (!url_is_external($path) && (\Drupal::service('router.route_provider')->getRoutesByPath('/' . $path)->count() > 0 || menu_get_item($path))) || empty($path) || $path == '<front>';
+}
+
+/**
  * Returns an array of shortcut links, suitable for rendering.
  *
  * @param \Drupal\shortcut\ShortcutSetInterface $shortcut_set
diff --git a/core/modules/system/src/Tests/Routing/MockRouteProvider.php b/core/modules/system/src/Tests/Routing/MockRouteProvider.php
index dce1b27..c13f53e 100644
--- a/core/modules/system/src/Tests/Routing/MockRouteProvider.php
+++ b/core/modules/system/src/Tests/Routing/MockRouteProvider.php
@@ -71,8 +71,29 @@ public function getRoutesByNames($names) {
   /**
    * {@inheritdoc}
    */
-  public function getRoutesByPattern($pattern) {
-    return new RouteCollection();
+  public function getRoutesByExactPattern($pattern) {
+    $collection = new RouteCollection();
+    foreach ($this->routes->all() as $name => $route) {
+      if ($route->getPath() == $pattern) {
+        $collection->add($name, $route);
+      }
+    }
+
+    return $collection;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRoutesByPath($path) {
+    $collection = new RouteCollection();
+    foreach ($this->routes->all() as $name => $route) {
+      if (preg_match($route->compile()->getRegex(), $path, $matches)) {
+        $collection->add($name, $route);
+      }
+    }
+
+    return $collection;
   }
 
   /**
diff --git a/core/modules/system/src/Tests/Routing/RouteProviderTest.php b/core/modules/system/src/Tests/Routing/RouteProviderTest.php
index be8862c..00c4411 100644
--- a/core/modules/system/src/Tests/Routing/RouteProviderTest.php
+++ b/core/modules/system/src/Tests/Routing/RouteProviderTest.php
@@ -335,6 +335,9 @@ function testOutlinePathNoMatch() {
 
     $request = Request::create($path, 'GET');
 
+    try {
+      $routes = $provider->getRoutesByPath($path);
+      $this->assertFalse(count($routes), 'No path found with this pattern.');
 
     $routes = $provider->getRoutesByPattern($path);
     $this->assertFalse(count($routes), 'No path found with this pattern.');
@@ -359,7 +362,7 @@ function testSystemPathMatch() {
     $request = Request::create('/path/one', 'GET');
     $request->attributes->set('_system_path', 'path/two');
 
-    $routes_by_pattern = $provider->getRoutesByPattern('/path/two');
+    $routes_by_pattern = $provider->getRoutesByExactPattern('/path/two');
     $routes = $provider->getRouteCollectionForRequest($request);
     $this->assertEqual(array_keys($routes_by_pattern->all()), array_keys($routes->all()), 'Ensure the expected routes are found.');
 
@@ -432,7 +435,7 @@ public function testGetRoutesByPatternWithLongPatterns() {
     $dumper->addRoutes($collection);
     $dumper->dump();
 
-    $result = $provider->getRoutesByPattern($path_to_test);
+    $result = $provider->getRoutesByPath('/test/1/test2/2/test3/3/4/5/6/test4');
     $this->assertEqual($result->count(), 1);
     // We can't compare the values of the routes directly, nor use
     // spl_object_hash() because they are separate instances.
