From: Douglas Gregor Date: Mon, 12 Apr 2010 16:00:01 +0000 (+0000) Subject: Fix a crash-on-invalid involving name lookup of tag names, where we X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=57265e35292897e383d70bbd1d552209fac37b39;p=clang Fix a crash-on-invalid involving name lookup of tag names, where we ended up finding a function template that we didn't expect. Recover more gracefully, and fix a similar issue for class templates. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101040 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 8bdc31ef32..aa24e395f0 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2200,6 +2200,8 @@ def err_typecheck_deleted_function : Error< "conversion function from %0 to %1 invokes a deleted function">; def err_expected_class_or_namespace : Error<"expected a class or namespace">; +def err_missing_qualified_for_redecl : Error< + "must qualify the name %0 to declare %q1 in this scope">; def err_invalid_declarator_scope : Error< "definition or redeclaration of %0 not in a namespace enclosing %1">; def err_invalid_declarator_global_scope : Error< diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 8e0e369af8..a4d8651212 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4948,8 +4948,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } if (!Previous.empty()) { - assert(Previous.isSingleResult()); - NamedDecl *PrevDecl = Previous.getFoundDecl(); + NamedDecl *PrevDecl = (*Previous.begin())->getUnderlyingDecl(); if (TagDecl *PrevTagDecl = dyn_cast(PrevDecl)) { // If this is a use of a previous tag, or if the tag is already declared // in the same scope (so that the definition/declaration completes or diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 285495a41b..d1577a5ab6 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -748,10 +748,12 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, LookupName(Previous, S); } - assert(!Previous.isAmbiguous() && "Ambiguity in class template redecl?"); + if (Previous.isAmbiguous()) + return true; + NamedDecl *PrevDecl = 0; if (Previous.begin() != Previous.end()) - PrevDecl = *Previous.begin(); + PrevDecl = (*Previous.begin())->getUnderlyingDecl(); // If there is a previous declaration with the same name, check // whether this is a valid redeclaration. @@ -804,7 +806,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, } } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S)) PrevDecl = PrevClassTemplate = 0; - + if (PrevClassTemplate) { // Ensure that the template parameter lists are compatible. if (!TemplateParameterListsAreEqual(TemplateParams, @@ -861,9 +863,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, TPC_ClassTemplate)) Invalid = true; - // FIXME: If we had a scope specifier, we better have a previous template - // declaration! - + if (SS.isSet()) { + // If the name of the template was qualified, we must be defining the + // template out-of-line. + if (!SS.isInvalid() && !Invalid && !PrevClassTemplate && + !(TUK == TUK_Friend && CurContext->isDependentContext())) + Diag(NameLoc, diag::err_member_def_does_not_match) + << Name << SemanticContext << SS.getRange(); + } + CXXRecordDecl *NewClass = CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, KWLoc, PrevClassTemplate? diff --git a/test/CXX/temp/temp.decls/temp.mem/p1.cpp b/test/CXX/temp/temp.decls/temp.mem/p1.cpp index b057eedf93..f5f12055c1 100644 --- a/test/CXX/temp/temp.decls/temp.mem/p1.cpp +++ b/test/CXX/temp/temp.decls/temp.mem/p1.cpp @@ -19,17 +19,17 @@ namespace PR6376 { template struct X { template - struct Y { }; + struct Y1 { }; // }; template<> struct X { template - struct Y { }; + struct Y1 { }; }; template - struct Z : public X::template Y { }; + struct Z : public X::template Y1 { }; Z z0; } diff --git a/test/SemaTemplate/class-template-decl.cpp b/test/SemaTemplate/class-template-decl.cpp index 71aabe97f4..1be1bc070a 100644 --- a/test/SemaTemplate/class-template-decl.cpp +++ b/test/SemaTemplate/class-template-decl.cpp @@ -51,3 +51,8 @@ void f() { } template class X1 { } var; // expected-error{{declared as a template}} + +namespace M { +} + +template class M::C3 { }; // expected-error{{out-of-line definition of 'C3' does not match any declaration in namespace 'M'}} diff --git a/test/SemaTemplate/friend.cpp b/test/SemaTemplate/friend.cpp index 61ef1865da..99685f2396 100644 --- a/test/SemaTemplate/friend.cpp +++ b/test/SemaTemplate/friend.cpp @@ -12,3 +12,22 @@ void f() { struct C0 { friend struct A; }; + +namespace PR6770 { + namespace N { + int f1(int); + } + using namespace N; + + namespace M { + float f1(float); + } + using M::f1; + + template void f1(T, T); + template + void f() { + friend class f; // expected-error{{'friend' used outside of class}} + friend class f1; // expected-error{{ 'friend' used outside of class}} + } +}