r210607 - Recover from missing typenames on template args for MSVC compatibility
Reid Kleckner
reid at kleckner.net
Tue Jun 10 16:29:48 PDT 2014
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 at +4 {{omitted 'typename' is a Microsoft extension}}
+#else
+ // expected-error at +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 at +4 {{omitted 'typename' is a Microsoft extension}}
+#else
+ // expected-error at +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 at +4 {{omitted 'typename' is a Microsoft extension}}
+#else
+ // expected-error at +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 at +4 {{omitted 'typename' is a Microsoft extension}}
+#else
+ // expected-error at +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 at +4 {{omitted 'typename' is a Microsoft extension}}
+#else
+ // expected-error at +2 {{must be a type; did you forget 'typename'?}}
+#endif
+ Bar<T::TypeInBase> y;
+
+#ifdef MSVC
+ // expected-warning at +4 {{omitted 'typename' is a Microsoft extension}}
+#else
+ // expected-error at +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 at +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 at +1 {{missing 'typename' prior to dependent type name 'B::type_or_int'}}
+template <typename T> void g() { T::type_or_int * x; }
+// expected-error at +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
More information about the cfe-commits
mailing list