Check for out-of-range bindings during IO mapping.
diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp
index 5d30ac2..f0a4f93 100644
--- a/StandAlone/StandAlone.cpp
+++ b/StandAlone/StandAlone.cpp
@@ -584,6 +584,12 @@
     if (! (Options & EOptionOutputPreprocessed) && ! program.link(messages))
         LinkFailed = true;
 
+    // Map IO
+    if (Options & EOptionSpv) {
+        if (!program.mapIO())
+            LinkFailed = true;
+    }
+    
     // Report
     if (! (Options & EOptionSuppressInfolog) &&
         ! (Options & EOptionMemoryLeakMode)) {
@@ -591,10 +597,6 @@
         PutsIfNonEmpty(program.getInfoDebugLog());
     }
 
-    // Map IO
-    if (Options & EOptionSpv)
-        program.mapIO();
-    
     // Reflect
     if (Options & EOptionDumpReflection) {
         program.buildReflection();
diff --git a/Test/baseResults/spv.register.autoassign.rangetest.frag.out b/Test/baseResults/spv.register.autoassign.rangetest.frag.out
new file mode 100644
index 0000000..a521a13
--- /dev/null
+++ b/Test/baseResults/spv.register.autoassign.rangetest.frag.out
@@ -0,0 +1,12 @@
+spv.register.autoassign.rangetest.frag
+
+Linked fragment stage:
+
+INTERNAL ERROR: mapped binding out of range: g_tScene
+INTERNAL ERROR: mapped binding out of range: g_tSamp
+INTERNAL ERROR: mapped binding out of range: g_tScene
+INTERNAL ERROR: mapped binding out of range: g_tSamp
+INTERNAL ERROR: mapped binding out of range: g_tSamp
+INTERNAL ERROR: mapped binding out of range: g_tScene
+
+SPIR-V is not generated for failed compile or link
diff --git a/Test/spv.register.autoassign.rangetest.frag b/Test/spv.register.autoassign.rangetest.frag
new file mode 100644
index 0000000..c81c395
--- /dev/null
+++ b/Test/spv.register.autoassign.rangetest.frag
@@ -0,0 +1,15 @@
+
+SamplerState g_tSamp : register(s5);
+
+Texture2D g_tScene[2] : register(t5);
+
+struct PS_OUTPUT
+{
+    float4 Color : SV_Target0;
+};
+
+void main(out PS_OUTPUT psout)
+{
+    psout.Color = g_tScene[0].Sample(g_tSamp, 0.3) +
+                  g_tScene[1].Sample(g_tSamp, 0.3);
+}
diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp
index e00638b..5333af4 100644
--- a/glslang/MachineIndependent/ShaderLang.cpp
+++ b/glslang/MachineIndependent/ShaderLang.cpp
@@ -1724,7 +1724,7 @@
 
     for (int s = 0; s < EShLangCount; ++s) {
         if (intermediate[s]) {
-            if (! ioMapper->addStage((EShLanguage)s, *intermediate[s]))
+            if (! ioMapper->addStage((EShLanguage)s, *intermediate[s], *infoSink))
                 return false;
         }
     }
diff --git a/glslang/MachineIndependent/iomapper.cpp b/glslang/MachineIndependent/iomapper.cpp
index d69cc13..15847dd 100644
--- a/glslang/MachineIndependent/iomapper.cpp
+++ b/glslang/MachineIndependent/iomapper.cpp
@@ -34,6 +34,7 @@
 //
 
 #include "../Include/Common.h"
+#include "../Include/InfoSink.h"
 #include "iomapper.h"
 #include "LiveTraverser.h"
 #include "localintermediate.h"
@@ -150,11 +151,30 @@
 class TIoMappingTraverser : public TBindingTraverser {
 public:
     TIoMappingTraverser(TIntermediate& i, TBindingMap& bindingMap, TUsedBindings& usedBindings,
-                        bool traverseDeadCode) :
-        TBindingTraverser(i, bindingMap, usedBindings, traverseDeadCode)
+                        TInfoSink& infoSink, bool traverseDeadCode) :
+        TBindingTraverser(i, bindingMap, usedBindings, traverseDeadCode),
+        infoSink(infoSink),
+        assignError(false)
     { }
 
+    bool success() const { return !assignError; }
+
 protected:
+    unsigned checkBindingRange(const TIntermSymbol& base, unsigned binding)
+    {
+        if (binding >= TQualifier::layoutBindingEnd) {
+            TString err = "mapped binding out of range: ";
+            err += base.getName();
+
+            infoSink.info.message(EPrefixInternalError, err.c_str());
+            assignError = true;
+            
+            return 0;
+        }
+
+        return binding;
+    }
+
     void addUniform(TIntermSymbol& base) override
     {
         // Skip things we don't intend to bind.
@@ -165,7 +185,7 @@
 
         // Apply existing binding, if we were given one or already made one up.
         if (existingBinding != -1) {
-            base.getWritableType().getQualifier().layoutBinding = existingBinding;
+            base.getWritableType().getQualifier().layoutBinding = checkBindingRange(base, existingBinding);
             return;
         }
 
@@ -174,7 +194,7 @@
             const int freeBinding = getFreeBinding(base.getType(), getBindingBase(base.getType()));
 
             markBinding(base, freeBinding);
-            base.getWritableType().getQualifier().layoutBinding = freeBinding;
+            base.getWritableType().getQualifier().layoutBinding = checkBindingRange(base, freeBinding);
         }
     }
 
@@ -195,13 +215,17 @@
 
         return nextBinding;
     }
+
+private:
+    bool assignError;  // true if there was an error assigning the bindings
+    TInfoSink& infoSink;
 };
 
 // Map I/O variables to provided offsets, and make bindings for
 // unbound but live variables.
 //
 // Returns false if the input is too malformed to do this.
-bool TIoMapper::addStage(EShLanguage, TIntermediate& intermediate)
+bool TIoMapper::addStage(EShLanguage, TIntermediate& intermediate, TInfoSink& infoSink)
 {
     // Trivial return if there is nothing to do.
     if (intermediate.getShiftSamplerBinding() == 0 &&
@@ -223,7 +247,7 @@
 
     TBindingTraverser it_binding_all(intermediate, bindingMap, usedBindings, true);
     TBindingTraverser it_binding_live(intermediate, bindingMap, usedBindings, false);
-    TIoMappingTraverser it_iomap(intermediate, bindingMap, usedBindings, true);
+    TIoMappingTraverser it_iomap(intermediate, bindingMap, usedBindings, infoSink, true);
 
     // Traverse all (live+dead) code to find explicit bindings, so we can avoid those.
     root->traverse(&it_binding_all);
@@ -240,7 +264,7 @@
     // Bind everything that needs a binding and doesn't have one.
     root->traverse(&it_iomap);
 
-    return true;
+    return it_iomap.success();
 }
 
 } // end namespace glslang
diff --git a/glslang/MachineIndependent/iomapper.h b/glslang/MachineIndependent/iomapper.h
index 69ed4c5..68dec77 100644
--- a/glslang/MachineIndependent/iomapper.h
+++ b/glslang/MachineIndependent/iomapper.h
@@ -42,6 +42,8 @@
 // A reflection database and its interface, consistent with the OpenGL API reflection queries.
 //
 
+class TInfoSink;
+
 namespace glslang {
 
 class TIntermediate;
@@ -53,7 +55,7 @@
     virtual ~TIoMapper() {}
 
     // grow the reflection stage by stage
-    bool addStage(EShLanguage, TIntermediate&);
+    bool addStage(EShLanguage, TIntermediate&, TInfoSink&);
 };
 
 } // end namespace glslang
diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp
index ee27db2..d0296f8 100644
--- a/gtests/Spv.FromFile.cpp
+++ b/gtests/Spv.FromFile.cpp
@@ -285,6 +285,10 @@
         { "spv.register.noautoassign.frag", "main_ep", 5, 10, 15, false, false },
         { "spv.register.autoassign-2.frag", "main", 5, 10, 15, true, true },
         { "spv.buffer.autoassign.frag", "main", 5, 10, 15, true, true },
+        { "spv.register.autoassign.rangetest.frag", "main", 
+                glslang::TQualifier::layoutBindingEnd-2,
+                glslang::TQualifier::layoutBindingEnd+5,
+                20, true, false },
     }),
     FileNameAsCustomTestSuffixIoMap
 );