[cfe-commits] r80056 - in /cfe/trunk: include/clang/AST/NestedNameSpecifier.h include/clang/Basic/Diagnostic.h include/clang/Basic/DiagnosticSemaKinds.td lib/AST/NestedNameSpecifier.cpp lib/Basic/Diagnostic.cpp lib/Sema/Sema.cpp lib/Sema/SemaCXXScopeSpec.cpp lib/Sema/SemaDecl.cpp test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp test/SemaTemplate/nested-template.cpp

Douglas Gregor dgregor at apple.com
Tue Aug 25 17:04:55 PDT 2009


Author: dgregor
Date: Tue Aug 25 19:04:55 2009
New Revision: 80056

URL: http://llvm.org/viewvc/llvm-project?rev=80056&view=rev
Log:
Improve diagnostics and recovery when the nested-name-specifier of a
qualified name does not actually refer into a class/class
template/class template partial specialization. 

Improve printing of nested-name-specifiers to eliminate redudant
qualifiers. Also, make it possible to output a nested-name-specifier
through a DiagnosticBuilder, although there are relatively few places
that will use this leeway.

Modified:
    cfe/trunk/include/clang/AST/NestedNameSpecifier.h
    cfe/trunk/include/clang/Basic/Diagnostic.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/NestedNameSpecifier.cpp
    cfe/trunk/lib/Basic/Diagnostic.cpp
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp
    cfe/trunk/test/SemaTemplate/nested-template.cpp

Modified: cfe/trunk/include/clang/AST/NestedNameSpecifier.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/NestedNameSpecifier.h?rev=80056&r1=80055&r2=80056&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/NestedNameSpecifier.h (original)
+++ cfe/trunk/include/clang/AST/NestedNameSpecifier.h Tue Aug 25 19:04:55 2009
@@ -14,6 +14,7 @@
 #ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
 #define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
 
+#include "clang/Basic/Diagnostic.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/PointerIntPair.h"
 
@@ -179,6 +180,15 @@
   void dump(const LangOptions &LO);
 };
 
+/// Insertion operator for diagnostics.  This allows sending NestedNameSpecifiers
+/// into a diagnostic with <<.
+inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+                                           NestedNameSpecifier *NNS) {
+  DB.AddTaggedVal(reinterpret_cast<intptr_t>(NNS), 
+                  Diagnostic::ak_nestednamespec);
+  return DB;
+}
+  
 }
 
 #endif

Modified: cfe/trunk/include/clang/Basic/Diagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Diagnostic.h?rev=80056&r1=80055&r2=80056&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/Diagnostic.h (original)
+++ cfe/trunk/include/clang/Basic/Diagnostic.h Tue Aug 25 19:04:55 2009
@@ -156,7 +156,8 @@
     ak_identifierinfo,  // IdentifierInfo
     ak_qualtype,        // QualType
     ak_declarationname, // DeclarationName
-    ak_nameddecl        // NamedDecl *
+    ak_nameddecl,       // NamedDecl *
+    ak_nestednamespec   // NestedNameSpecifier *
   };
 
 private: 

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=80056&r1=80055&r2=80056&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Aug 25 19:04:55 2009
@@ -889,8 +889,8 @@
   "extraneous template parameter list in template specialization or "
   "out-of-line template definition">;
 def err_template_qualified_declarator_no_match : Error<
-  "nested name specifier '%0' for declaration does not refer to a class "
-  "template or class template partial specialization">;
+  "nested name specifier %0 for declaration does not refer into a class, "
+  "class template or class template partial specialization">;
 def err_template_spec_decl_out_of_scope_global : Error<
   "class template %select{|partial }0specialization of %1 must occur in the "
   "global scope">;

Modified: cfe/trunk/lib/AST/NestedNameSpecifier.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/NestedNameSpecifier.cpp?rev=80056&r1=80055&r2=80056&view=diff

==============================================================================
--- cfe/trunk/lib/AST/NestedNameSpecifier.cpp (original)
+++ cfe/trunk/lib/AST/NestedNameSpecifier.cpp Tue Aug 25 19:04:55 2009
@@ -131,15 +131,33 @@
     std::string TypeStr;
     Type *T = getAsType();
 
-    // If this is a qualified name type, suppress the qualification:
-    // it's part of our nested-name-specifier sequence anyway.  FIXME:
-    // We should be able to assert that this doesn't happen.
-    if (const QualifiedNameType *QualT = dyn_cast<QualifiedNameType>(T))
-      T = QualT->getNamedType().getTypePtr();
-    
     PrintingPolicy InnerPolicy(Policy);
     InnerPolicy.SuppressTagKind = true;
-    T->getAsStringInternal(TypeStr, InnerPolicy);
+    
+    // Nested-name-specifiers are intended to contain minimally-qualified
+    // types. An actual QualifiedNameType will not occur, since we'll store
+    // just the type that is referred to in the nested-name-specifier (e.g.,
+    // a TypedefType, TagType, etc.). However, when we are dealing with
+    // dependent template-id types (e.g., Outer<T>::template Inner<U>), 
+    // the type requires its own nested-name-specifier for uniqueness, so we
+    // suppress that nested-name-specifier during printing.
+    assert(!isa<QualifiedNameType>(T) && 
+           "Qualified name type in nested-name-specifier");
+    if (const TemplateSpecializationType *SpecType
+          = dyn_cast<TemplateSpecializationType>(T)) {
+      // Print the template name without its corresponding 
+      // nested-name-specifier.
+      SpecType->getTemplateName().print(OS, InnerPolicy, true);
+      
+      // Print the template argument list.
+      TypeStr = TemplateSpecializationType::PrintTemplateArgumentList(
+                                                          SpecType->getArgs(), 
+                                                       SpecType->getNumArgs(), 
+                                                                 InnerPolicy);
+    } else {
+      // Print the type normally
+      T->getAsStringInternal(TypeStr, InnerPolicy);
+    }
     OS << TypeStr;
     break;
   }

Modified: cfe/trunk/lib/Basic/Diagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Diagnostic.cpp?rev=80056&r1=80055&r2=80056&view=diff

==============================================================================
--- cfe/trunk/lib/Basic/Diagnostic.cpp (original)
+++ cfe/trunk/lib/Basic/Diagnostic.cpp Tue Aug 25 19:04:55 2009
@@ -797,6 +797,7 @@
     case Diagnostic::ak_qualtype:
     case Diagnostic::ak_declarationname:
     case Diagnostic::ak_nameddecl:
+    case Diagnostic::ak_nestednamespec:
       getDiags()->ConvertArgToString(getArgKind(ArgNo), getRawArg(ArgNo),
                                      Modifier, ModifierLen,
                                      Argument, ArgumentLen, OutStr);

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=80056&r1=80055&r2=80056&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Tue Aug 25 19:04:55 2009
@@ -79,8 +79,7 @@
     else
       assert(ModLen == 0 && ArgLen == 0 &&
              "Invalid modifier for DeclarationName argument");
-  } else {
-    assert(Kind == Diagnostic::ak_nameddecl);
+  } else if (Kind == Diagnostic::ak_nameddecl) {
     if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
       S = reinterpret_cast<NamedDecl*>(Val)->getQualifiedNameAsString();
     else { 
@@ -88,6 +87,11 @@
            "Invalid modifier for NamedDecl* argument");
       S = reinterpret_cast<NamedDecl*>(Val)->getNameAsString();
     }
+  } else {
+    llvm::raw_string_ostream OS(S);
+    assert(Kind == Diagnostic::ak_nestednamespec);
+    reinterpret_cast<NestedNameSpecifier*> (Val)->print(OS, 
+                                                        Context.PrintingPolicy);
   }
   
   Output.push_back('\'');

Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=80056&r1=80055&r2=80056&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Tue Aug 25 19:04:55 2009
@@ -79,17 +79,6 @@
         // The nested name specifier refers to a member of a class template.
         return RecordT->getDecl();
       }
-      
-      std::string NNSString;
-      {
-        llvm::raw_string_ostream OS(NNSString);
-        NNS->print(OS, Context.PrintingPolicy);
-      }
-      
-      // FIXME: Allow us to pass a nested-name-specifier to Diag?
-      Diag(SS.getRange().getBegin(), 
-           diag::err_template_qualified_declarator_no_match)
-        << NNSString << SS.getRange();
     }
     
     return 0;
@@ -298,6 +287,9 @@
                                            T.getTypePtr());
     }
     
+    // FIXME: It would be nice to maintain the namespace alias name, then
+    // see through that alias when resolving the nested-name-specifier down to
+    // a declaration context.
     if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD))
       return NestedNameSpecifier::Create(Context, Prefix,
                                          Alias->getNamespace());
@@ -404,8 +396,6 @@
   assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
   if (DeclContext *DC = computeDeclContext(SS, true))
     EnterDeclaratorContext(S, DC);
-  else
-    const_cast<CXXScopeSpec&>(SS).setScopeRep(0);
 }
 
 /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously
@@ -415,8 +405,8 @@
 /// defining scope.
 void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
   assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
-  assert((SS.isInvalid() || S->getEntity() == computeDeclContext(SS, true)) && 
-         "Context imbalance!");
-  if (!SS.isInvalid())
+  if (SS.isInvalid())
+    return;
+  if (computeDeclContext(SS, true))
     ExitDeclaratorContext(S);
 }

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=80056&r1=80055&r2=80056&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Aug 25 19:04:55 2009
@@ -1633,7 +1633,7 @@
         << D.getDeclSpec().getSourceRange() << D.getSourceRange();
     return DeclPtrTy();
   }
-  
+   
   // The scope passed in may not be a decl scope.  Zip up the scope tree until
   // we find one that is.
   while ((S->getFlags() & Scope::DeclScope) == 0 ||
@@ -1701,7 +1701,19 @@
                           D.getIdentifierLoc());
   } else { // Something like "int foo::x;"
     DC = computeDeclContext(D.getCXXScopeSpec(), true);
-    // FIXME: RequireCompleteDeclContext(D.getCXXScopeSpec()); ?
+    
+    if (!DC) {
+      // If we could not compute the declaration context, it's because the
+      // declaration context is dependent but does not refer to a class,
+      // class template, or class template partial specialization. Complain
+      // and return early, to avoid the coming semantic disaster.
+      Diag(D.getIdentifierLoc(), 
+           diag::err_template_qualified_declarator_no_match)
+        << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep()
+        << D.getCXXScopeSpec().getRange();
+      return DeclPtrTy();
+    }
+    
     PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName, true);
 
     // C++ 7.3.1.2p2:

Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp?rev=80056&r1=80055&r2=80056&view=diff

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp Tue Aug 25 19:04:55 2009
@@ -43,7 +43,7 @@
 }
 
 template<class X, class Y> 
-void X0<Y, X>::f4() { } // expected-error{{does not refer to}}
+void X0<Y, X>::f4() { } // expected-error{{does not refer}}
 
 // FIXME: error message should probably say, "redefinition of 'X0<T, U>::f0'"
 // rather than just "redefinition of 'f0'"

Modified: cfe/trunk/test/SemaTemplate/nested-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/nested-template.cpp?rev=80056&r1=80055&r2=80056&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/nested-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/nested-template.cpp Tue Aug 25 19:04:55 2009
@@ -87,3 +87,7 @@
 template<typename X>
 template<typename Y>
 Y Outer<X>::Inner1<Y>::ReallyInner::value3 = Y();
+
+template<typename X>
+template<typename Y>
+Y Outer<X>::Inner1<Y*>::ReallyInner::value4; // expected-error{{Outer<X>::Inner1<Y *>::ReallyInner::}}





More information about the cfe-commits mailing list