Author: rnk Date: Tue Jun 10 18:29:48 2014 New Revision: 210607 URL: http://llvm.org/viewvc/llvm-project?rev=210607&view=rev Log: Recover from missing typenames on template args for MSVC compatibility
While matching a non-type template argument against a known template type parameter we now modify the AST's TemplateArgumentLoc to assume the user wrote typename. Under -fms-compatibility, we downgrade our diagnostic from an error to an extwarn. Reviewed by: rsmith Differential Revision: http://reviews.llvm.org/D4049 Modified: cfe/trunk/include/clang/AST/TemplateBase.h cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/test/SemaTemplate/typename-specifier.cpp Modified: cfe/trunk/include/clang/AST/TemplateBase.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TemplateBase.h?rev=210607&r1=210606&r2=210607&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/TemplateBase.h (original) +++ cfe/trunk/include/clang/AST/TemplateBase.h Tue Jun 10 18:29:48 2014 @@ -543,6 +543,10 @@ public: return Arguments[I]; } + TemplateArgumentLoc &operator[](unsigned I) { + return Arguments[I]; + } + void addArgument(const TemplateArgumentLoc &Loc) { Arguments.push_back(Loc); } Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=210607&r1=210606&r2=210607&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jun 10 18:29:48 2014 @@ -3111,6 +3111,10 @@ def err_template_arg_must_be_type : Erro "template argument for template type parameter must be a type">; def err_template_arg_must_be_type_suggest : Error< "template argument for template type parameter must be a type; did you forget 'typename'?">; +def ext_ms_template_type_arg_missing_typename : ExtWarn< + "template argument for template type parameter must be a type; " + "omitted 'typename' is a Microsoft extension">, + InGroup<Microsoft>; def err_template_arg_must_be_expr : Error< "template argument for non-type template parameter must be an expression">; def err_template_arg_nontype_ambig : Error< Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=210607&r1=210606&r2=210607&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Tue Jun 10 18:29:48 2014 @@ -5397,7 +5397,7 @@ public: }; bool CheckTemplateArgument(NamedDecl *Param, - const TemplateArgumentLoc &Arg, + TemplateArgumentLoc &Arg, NamedDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, @@ -5433,7 +5433,7 @@ public: SmallVectorImpl<TemplateArgument> &Converted); bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, - const TemplateArgumentLoc &Arg, + TemplateArgumentLoc &Arg, SmallVectorImpl<TemplateArgument> &Converted); bool CheckTemplateArgument(TemplateTypeParmDecl *Param, @@ -5443,7 +5443,7 @@ public: TemplateArgument &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, - const TemplateArgumentLoc &Arg, + TemplateArgumentLoc &Arg, unsigned ArgumentPackIndex); ExprResult Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=210607&r1=210606&r2=210607&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Jun 10 18:29:48 2014 @@ -2181,6 +2181,17 @@ Sema::BuildQualifiedDeclarationNameExpr( return ExprError(); } + if (R.isSingleResult() && R.getAsSingle<TypeDecl>()) { + // Diagnose a missing typename if this resolved unambiguously to a type in a + // dependent context. + // FIXME: Issue a fixit and recover as though the user had written + // 'typename'. + Diag(SS.getBeginLoc(), diag::err_typename_missing) + << SS.getScopeRep() << NameInfo.getName().getAsString() + << SourceRange(SS.getBeginLoc(), NameInfo.getEndLoc()); + return ExprError(); + } + // Defend against this resolving to an implicit member access. We usually // won't get here if this might be a legitimate a class member (we end up in // BuildMemberReferenceExpr instead), but this can be valid if we're forming Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=210607&r1=210606&r2=210607&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Jun 10 18:29:48 2014 @@ -2999,9 +2999,11 @@ TemplateNameKind Sema::ActOnDependentTem } bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, - const TemplateArgumentLoc &AL, + TemplateArgumentLoc &AL, SmallVectorImpl<TemplateArgument> &Converted) { const TemplateArgument &Arg = AL.getArgument(); + QualType ArgType; + TypeSourceInfo *TSI = nullptr; // Check template type parameter. switch(Arg.getKind()) { @@ -3009,6 +3011,8 @@ bool Sema::CheckTemplateTypeArgument(Tem // C++ [temp.arg.type]p1: // A template-argument for a template-parameter which is a // type shall be a type-id. + ArgType = Arg.getAsType(); + TSI = AL.getTypeSourceInfo(); break; case TemplateArgument::Template: { // We have a template type parameter but the template argument @@ -3043,18 +3047,38 @@ bool Sema::CheckTemplateTypeArgument(Tem } } - if (NameInfo.getName().isIdentifier()) { + if (auto *II = NameInfo.getName().getAsIdentifierInfo()) { LookupResult Result(*this, NameInfo, LookupOrdinaryName); LookupParsedName(Result, CurScope, &SS); if (Result.getAsSingle<TypeDecl>() || Result.getResultKind() == - LookupResult::NotFoundInCurrentInstantiation) { - // FIXME: Add a FixIt and fix up the template argument for recovery. + LookupResult::NotFoundInCurrentInstantiation) { + // Suggest that the user add 'typename' before the NNS. SourceLocation Loc = AL.getSourceRange().getBegin(); - Diag(Loc, diag::err_template_arg_must_be_type_suggest); + Diag(Loc, getLangOpts().MSVCCompat + ? diag::ext_ms_template_type_arg_missing_typename + : diag::err_template_arg_must_be_type_suggest) + << FixItHint::CreateInsertion(Loc, "typename "); Diag(Param->getLocation(), diag::note_template_param_here); - return true; + + // Recover by synthesizing a type using the location information that we + // already have. + ArgType = + Context.getDependentNameType(ETK_Typename, SS.getScopeRep(), II); + TypeLocBuilder TLB; + DependentNameTypeLoc TL = TLB.push<DependentNameTypeLoc>(ArgType); + TL.setElaboratedKeywordLoc(SourceLocation(/*synthesized*/)); + TL.setQualifierLoc(SS.getWithLocInContext(Context)); + TL.setNameLoc(NameInfo.getLoc()); + TSI = TLB.getTypeSourceInfo(Context, ArgType); + + // Overwrite our input TemplateArgumentLoc so that we can recover + // properly. + AL = TemplateArgumentLoc(TemplateArgument(ArgType), + TemplateArgumentLocInfo(TSI)); + + break; } } // fallthrough @@ -3070,11 +3094,11 @@ bool Sema::CheckTemplateTypeArgument(Tem } } - if (CheckTemplateArgument(Param, AL.getTypeSourceInfo())) + if (CheckTemplateArgument(Param, TSI)) return true; // Add the converted template type argument. - QualType ArgType = Context.getCanonicalType(Arg.getAsType()); + ArgType = Context.getCanonicalType(ArgType); // Objective-C ARC: // If an explicitly-specified template argument type is a lifetime type @@ -3356,7 +3380,7 @@ Sema::SubstDefaultTemplateArgumentIfAvai /// /// \returns true on error, false otherwise. bool Sema::CheckTemplateArgument(NamedDecl *Param, - const TemplateArgumentLoc &Arg, + TemplateArgumentLoc &Arg, NamedDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, @@ -5078,7 +5102,7 @@ ExprResult Sema::CheckTemplateArgument(N /// This routine implements the semantics of C++ [temp.arg.template]. /// It returns true if an error occurred, and false otherwise. bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, - const TemplateArgumentLoc &Arg, + TemplateArgumentLoc &Arg, unsigned ArgumentPackIndex) { TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern(); TemplateDecl *Template = Name.getAsTemplateDecl(); Modified: cfe/trunk/test/SemaTemplate/typename-specifier.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/typename-specifier.cpp?rev=210607&r1=210606&r2=210607&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/typename-specifier.cpp (original) +++ cfe/trunk/test/SemaTemplate/typename-specifier.cpp Tue Jun 10 18:29:48 2014 @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-unused +// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-unused -fms-compatibility -DMSVC namespace N { struct A { typedef int type; @@ -136,19 +137,106 @@ class ExampleClass1 { }; void foo() { - pair<ExampleItemSet::iterator, int> i; // expected-error {{template argument for template type parameter must be a type; did you forget 'typename'?}} +#ifdef MSVC + // expected-warning@+4 {{omitted 'typename' is a Microsoft extension}} +#else + // expected-error@+2 {{template argument for template type parameter must be a type; did you forget 'typename'?}} +#endif + pair<ExampleItemSet::iterator, int> i; pair<this->ExampleItemSet::iterator, int> i; // expected-error-re {{template argument for template type parameter must be a type{{$}}}} pair<ExampleItemSet::operator[], int> i; // expected-error-re {{template argument for template type parameter must be a type{{$}}}} } - pair<ExampleItemSet::iterator, int> elt; // expected-error {{template argument for template type parameter must be a type; did you forget 'typename'?}} +#ifdef MSVC + // expected-warning@+4 {{omitted 'typename' is a Microsoft extension}} +#else + // expected-error@+2 {{template argument for template type parameter must be a type; did you forget 'typename'?}} +#endif + pair<ExampleItemSet::iterator, int> elt; typedef map<int, ExampleItem*> ExampleItemMap; static void bar() { - pair<ExampleItemMap::iterator, int> i; // expected-error {{template argument for template type parameter must be a type; did you forget 'typename'?}} +#ifdef MSVC + // expected-warning@+4 {{omitted 'typename' is a Microsoft extension}} +#else + // expected-error@+2 {{template argument for template type parameter must be a type; did you forget 'typename'?}} +#endif + pair<ExampleItemMap::iterator, int> i; } - pair<ExampleItemMap::iterator, int> entry; // expected-error {{template argument for template type parameter must be a type; did you forget 'typename'?}} +#ifdef MSVC + // expected-warning@+4 {{omitted 'typename' is a Microsoft extension}} +#else + // expected-error@+2 {{template argument for template type parameter must be a type; did you forget 'typename'?}} +#endif + pair<ExampleItemMap::iterator, int> entry; pair<bar, int> foobar; // expected-error {{template argument for template type parameter must be a type}} }; } // namespace missing_typename + +namespace missing_typename_and_base { +template <class T> struct Bar {}; // expected-note 1+ {{template parameter is declared here}} +template <typename T> +struct Foo : T { + + // FIXME: MSVC accepts this code. + Bar<TypeInBase> x; // expected-error {{use of undeclared identifier 'TypeInBase'}} + +#ifdef MSVC + // expected-warning@+4 {{omitted 'typename' is a Microsoft extension}} +#else + // expected-error@+2 {{must be a type; did you forget 'typename'?}} +#endif + Bar<T::TypeInBase> y; + +#ifdef MSVC + // expected-warning@+4 {{omitted 'typename' is a Microsoft extension}} +#else + // expected-error@+2 {{must be a type; did you forget 'typename'?}} +#endif + Bar<T::NestedRD::TypeInNestedRD> z; + +}; +struct Base { + typedef int TypeInBase; + struct NestedRD { + typedef int TypeInNestedRD; + }; +}; +Foo<Base> x; +} // namespace missing_typename_and_base + +namespace func_type_vs_construct_tmp { +template <typename> struct S { typedef int type; }; +template <typename T> void f(); +template <int N> void f(); + +// expected-error@+1 {{missing 'typename' prior to dependent type name 'S<int>::type'}} +template <typename T> void g() { f</*typename*/ S<T>::type(int())>(); } + +// Adding typename does fix the diagnostic. +template <typename T> void h() { f<typename S<T>::type(int())>(); } + +void j() { + g<int>(); // expected-note-re {{in instantiation {{.*}} requested here}} + h<int>(); +} +} // namespace func_type_vs_construct_tmp + +namespace pointer_vs_multiply { +int x; +// expected-error@+1 {{missing 'typename' prior to dependent type name 'B::type_or_int'}} +template <typename T> void g() { T::type_or_int * x; } +// expected-error@+1 {{typename specifier refers to non-type member 'type_or_int' in 'pointer_vs_multiply::A'}} +template <typename T> void h() { typename T::type_or_int * x; } + +struct A { static const int type_or_int = 5; }; // expected-note {{referenced member 'type_or_int' is declared here}} +struct B { typedef int type_or_int; }; + +void j() { + g<A>(); + g<B>(); // expected-note-re {{in instantiation {{.*}} requested here}} + h<A>(); // expected-note-re {{in instantiation {{.*}} requested here}} + h<B>(); +} +} // namespace pointer_vs_multiply _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
