From: Douglas Gregor Date: Wed, 13 Oct 2010 00:27:52 +0000 (+0000) Subject: Teach the warning about unnamed/local types in template arguments to X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5f3aeb6f8b1e1cc00015407ef6886429f9b7fb78;p=clang Teach the warning about unnamed/local types in template arguments to actually walk the template argument type to find any unnamed/local types within it. Fixes PR6784. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@116382 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 078669a556..4fef397f37 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -6731,7 +6731,7 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, case OR_Success: { FunctionDecl *FDecl = Best->Function; CheckUnresolvedLookupAccess(ULE, Best->FoundDecl); - DiagnoseUseOfDecl(FDecl? FDecl : Best->FoundDecl, ULE->getNameLoc()); + DiagnoseUseOfDecl(FDecl? FDecl : Best->FoundDecl.getDecl(), ULE->getNameLoc()); Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl); return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index a569a966fa..6434333fbe 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -20,6 +20,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/TypeVisitor.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Basic/LangOptions.h" @@ -2347,6 +2348,215 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, return Invalid; } +namespace { + class UnnamedLocalNoLinkageFinder + : public TypeVisitor + { + Sema &S; + SourceRange SR; + + typedef TypeVisitor inherited; + + public: + UnnamedLocalNoLinkageFinder(Sema &S, SourceRange SR) : S(S), SR(SR) { } + + bool Visit(QualType T) { + return inherited::Visit(T.getTypePtr()); + } + +#define TYPE(Class, Parent) \ + bool Visit##Class##Type(const Class##Type *); +#define ABSTRACT_TYPE(Class, Parent) \ + bool Visit##Class##Type(const Class##Type *) { return false; } +#define NON_CANONICAL_TYPE(Class, Parent) \ + bool Visit##Class##Type(const Class##Type *) { return false; } +#include "clang/AST/TypeNodes.def" + + bool VisitTagDecl(const TagDecl *Tag); + bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS); + }; +} + +bool UnnamedLocalNoLinkageFinder::VisitBuiltinType(const BuiltinType*) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitComplexType(const ComplexType* T) { + return Visit(T->getElementType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitPointerType(const PointerType* T) { + return Visit(T->getPointeeType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitBlockPointerType( + const BlockPointerType* T) { + return Visit(T->getPointeeType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitLValueReferenceType( + const LValueReferenceType* T) { + return Visit(T->getPointeeType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitRValueReferenceType( + const RValueReferenceType* T) { + return Visit(T->getPointeeType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitMemberPointerType( + const MemberPointerType* T) { + return Visit(T->getPointeeType()) || Visit(QualType(T->getClass(), 0)); +} + +bool UnnamedLocalNoLinkageFinder::VisitConstantArrayType( + const ConstantArrayType* T) { + return Visit(T->getElementType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitIncompleteArrayType( + const IncompleteArrayType* T) { + return Visit(T->getElementType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitVariableArrayType( + const VariableArrayType* T) { + return Visit(T->getElementType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitDependentSizedArrayType( + const DependentSizedArrayType* T) { + return Visit(T->getElementType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitDependentSizedExtVectorType( + const DependentSizedExtVectorType* T) { + return Visit(T->getElementType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitVectorType(const VectorType* T) { + return Visit(T->getElementType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitExtVectorType(const ExtVectorType* T) { + return Visit(T->getElementType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitFunctionProtoType( + const FunctionProtoType* T) { + for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(), + AEnd = T->arg_type_end(); + A != AEnd; ++A) { + if (Visit(*A)) + return true; + } + + return Visit(T->getResultType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitFunctionNoProtoType( + const FunctionNoProtoType* T) { + return Visit(T->getResultType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitUnresolvedUsingType( + const UnresolvedUsingType*) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitTypeOfExprType(const TypeOfExprType*) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitTypeOfType(const TypeOfType* T) { + return Visit(T->getUnderlyingType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitDecltypeType(const DecltypeType*) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitRecordType(const RecordType* T) { + return VisitTagDecl(T->getDecl()); +} + +bool UnnamedLocalNoLinkageFinder::VisitEnumType(const EnumType* T) { + return VisitTagDecl(T->getDecl()); +} + +bool UnnamedLocalNoLinkageFinder::VisitTemplateTypeParmType( + const TemplateTypeParmType*) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitTemplateSpecializationType( + const TemplateSpecializationType*) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitInjectedClassNameType( + const InjectedClassNameType* T) { + return VisitTagDecl(T->getDecl()); +} + +bool UnnamedLocalNoLinkageFinder::VisitDependentNameType( + const DependentNameType* T) { + return VisitNestedNameSpecifier(T->getQualifier()); +} + +bool UnnamedLocalNoLinkageFinder::VisitDependentTemplateSpecializationType( + const DependentTemplateSpecializationType* T) { + return VisitNestedNameSpecifier(T->getQualifier()); +} + +bool UnnamedLocalNoLinkageFinder::VisitObjCObjectType(const ObjCObjectType *) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitObjCInterfaceType( + const ObjCInterfaceType *) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitObjCObjectPointerType( + const ObjCObjectPointerType *) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) { + if (Tag->getDeclContext()->isFunctionOrMethod()) { + S.Diag(SR.getBegin(), diag::ext_template_arg_local_type) + << S.Context.getTypeDeclType(Tag) << SR; + return true; + } + + if (!Tag->getDeclName() && !Tag->getTypedefForAnonDecl()) { + S.Diag(SR.getBegin(), diag::ext_template_arg_unnamed_type) << SR; + S.Diag(Tag->getLocation(), diag::note_template_unnamed_type_here); + return true; + } + + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier( + NestedNameSpecifier *NNS) { + if (NNS->getPrefix() && VisitNestedNameSpecifier(NNS->getPrefix())) + return true; + + switch (NNS->getKind()) { + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::Global: + return false; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + return Visit(QualType(NNS->getAsType(), 0)); + } +} + + /// \brief Check a template argument against its corresponding /// template type parameter. /// @@ -2356,39 +2566,24 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, TypeSourceInfo *ArgInfo) { assert(ArgInfo && "invalid TypeSourceInfo"); QualType Arg = ArgInfo->getType(); + SourceRange SR = ArgInfo->getTypeLoc().getSourceRange(); + + if (Arg->isVariablyModifiedType()) { + return Diag(SR.getBegin(), diag::err_variably_modified_template_arg) << Arg; + } else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) { + return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR; + } // C++03 [temp.arg.type]p2: // A local type, a type with no linkage, an unnamed type or a type // compounded from any of these types shall not be used as a // template-argument for a template type-parameter. + // // C++0x allows these, and even in C++03 we allow them as an extension with // a warning. - // - // FIXME: We're not handling the "type compounded from any of these types" - // case. - SourceRange SR = ArgInfo->getTypeLoc().getSourceRange(); if (!LangOpts.CPlusPlus0x) { - const TagType *Tag = 0; - if (const EnumType *EnumT = Arg->getAs()) - Tag = EnumT; - else if (const RecordType *RecordT = Arg->getAs()) - Tag = RecordT; - if (Tag && Tag->getDecl()->getDeclContext()->isFunctionOrMethod()) { - SourceRange SR = ArgInfo->getTypeLoc().getSourceRange(); - Diag(SR.getBegin(), diag::ext_template_arg_local_type) - << QualType(Tag, 0) << SR; - } else if (Tag && !Tag->getDecl()->getDeclName() && - !Tag->getDecl()->getTypedefForAnonDecl()) { - Diag(SR.getBegin(), diag::ext_template_arg_unnamed_type) << SR; - Diag(Tag->getDecl()->getLocation(), - diag::note_template_unnamed_type_here); - } - } - - if (Arg->isVariablyModifiedType()) { - return Diag(SR.getBegin(), diag::err_variably_modified_template_arg) << Arg; - } else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) { - return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR; + UnnamedLocalNoLinkageFinder Finder(*this, SR); + (void)Finder.Visit(Context.getCanonicalType(Arg)); } return false; diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 2bc0e40b39..3230e02e54 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -1265,7 +1265,6 @@ namespace { struct PartialSpecMatchResult { ClassTemplatePartialSpecializationDecl *Partial; TemplateArgumentList *Args; - llvm::SmallVector Diagnostics; }; } @@ -1336,7 +1335,6 @@ Sema::InstantiateClassTemplateSpecialization( Matched.push_back(PartialSpecMatchResult()); Matched.back().Partial = Partial; Matched.back().Args = Info.take(); - Matched.back().Diagnostics.append(Info.diag_begin(), Info.diag_end()); } } @@ -1410,10 +1408,6 @@ Sema::InstantiateClassTemplateSpecialization( Pattern = OrigPartialSpec; ClassTemplateSpec->setInstantiationOf(Best->Partial, Best->Args); - - // Report any suppressed diagnostics. - for (unsigned I = 0, N = Best->Diagnostics.size(); I != N; ++I) - Diag(Best->Diagnostics[I].first, Best->Diagnostics[I].second); } else { // -- If no matches are found, the instantiation is generated // from the primary template. diff --git a/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp b/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp index 11bfe3e413..0fd9a7e884 100644 --- a/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp +++ b/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp @@ -25,7 +25,7 @@ namespace N0 { template int f1(T, U); enum {e1}; // expected-note 2{{unnamed type used in template argument was declared here}} enum {e2}; // expected-note 2{{unnamed type used in template argument was declared here}} - enum {e3}; // FIXME: expected unnamed type used in template argument was declared here + enum {e3}; // expected-note{{unnamed type used in template argument was declared here}} template struct X; template struct X { }; @@ -37,6 +37,6 @@ namespace N0 { f1(e2); // expected-warning{{template argument uses unnamed type}} f1(e2); - X<__typeof__(e3)*> x; // FIXME: should warn about unnamed type + X<__typeof__(e3)*> x; // expected-warning{{template argument uses unnamed type}} } }