diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 78010b7bb46e6f..0e95e237e97491 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -186,14 +186,14 @@ class CXXScopeSpec { SourceLocation getLastQualifierNameLoc() const; /// No scope specifier. - bool isEmpty() const { return !Range.isValid(); } + bool isEmpty() const { return Range.isInvalid() && getScopeRep() == nullptr; } /// A scope specifier is present, but may be valid or invalid. bool isNotEmpty() const { return !isEmpty(); } /// An error occurred during parsing of the scope specifier. - bool isInvalid() const { return isNotEmpty() && getScopeRep() == nullptr; } + bool isInvalid() const { return Range.isValid() && getScopeRep() == nullptr; } /// A scope specifier is present, and it refers to a real scope. - bool isValid() const { return isNotEmpty() && getScopeRep() != nullptr; } + bool isValid() const { return getScopeRep() != nullptr; } /// Indicate that this nested-name-specifier is invalid. void SetInvalid(SourceRange R) { diff --git a/clang/test/SemaCXX/nested-name-spec.cpp b/clang/test/SemaCXX/nested-name-spec.cpp index 725ac64cedb7c5..403bf1c0d4aa86 100644 --- a/clang/test/SemaCXX/nested-name-spec.cpp +++ b/clang/test/SemaCXX/nested-name-spec.cpp @@ -460,3 +460,16 @@ class B { }; } } + +namespace DependentTemplateInTrivialNNSLoc { + // This testcase causes us to create trivial type source info when doing + // substitution into T::template g<>. That trivial type source info contained + // a NestedNameSpecifierLoc with no location information. + // + // Previously, creating a CXXScopeSpec from that resulted in an invalid scope + // spec, leading to crashes. Ensure we don't crash here. + template void f(T &x) { + for (typename T::template g<> i : x) {} // expected-warning 0-1{{extension}} + x: goto x; + } +}