[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