Allow anonymous and local types. The support was already in place for these,

but this makes them work even as an extension in C++98. This resolves PR8077.

llvm-svn: 113011
This commit is contained in:
Chandler Carruth 2010-09-03 21:12:34 +00:00
parent 2a9de4d828
commit 9bb67f4d1a
6 changed files with 91 additions and 26 deletions

View File

@ -61,6 +61,7 @@ def : DiagGroup<"inline">;
def : DiagGroup<"int-to-pointer-cast">;
def : DiagGroup<"invalid-pch">;
def LiteralRange : DiagGroup<"literal-range">;
def LocalTypeTemplateArgs : DiagGroup<"local-type-template-args">;
def : DiagGroup<"main">;
def MissingBraces : DiagGroup<"missing-braces">;
def MissingDeclarations: DiagGroup<"missing-declarations">;
@ -130,6 +131,7 @@ def : DiagGroup<"type-limits">;
def Uninitialized : DiagGroup<"uninitialized">;
def UnknownPragmas : DiagGroup<"unknown-pragmas">;
def UnknownAttributes : DiagGroup<"unknown-attributes">;
def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args">;
def UnusedArgument : DiagGroup<"unused-argument">;
def UnusedExceptionParameter : DiagGroup<"unused-exception-parameter">;
def UnusedFunction : DiagGroup<"unused-function">;

View File

@ -1371,9 +1371,10 @@ def err_template_arg_nontype_ambig : Error<
"template argument for non-type template parameter is treated as type %0">;
def err_template_arg_must_be_template : Error<
"template argument for template template parameter must be a class template">;
def err_template_arg_local_type : Error<"template argument uses local type %0">;
def err_template_arg_unnamed_type : Error<
"template argument uses unnamed type">;
def ext_template_arg_local_type : ExtWarn<
"template argument uses local type %0">, InGroup<LocalTypeTemplateArgs>;
def ext_template_arg_unnamed_type : ExtWarn<
"template argument uses unnamed type">, InGroup<UnnamedTypeTemplateArgs>;
def note_template_unnamed_type_here : Note<
"unnamed type used in template argument was declared here">;
def err_template_arg_overload_type : Error<

View File

@ -2347,31 +2347,33 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
assert(ArgInfo && "invalid TypeSourceInfo");
QualType Arg = ArgInfo->getType();
// C++ [temp.arg.type]p2:
// 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.
//
// FIXME: Perform the unnamed type check.
// C++0x allows these, and even in C++03 we allow them as an extension with
// a warning.
SourceRange SR = ArgInfo->getTypeLoc().getSourceRange();
const TagType *Tag = 0;
if (const EnumType *EnumT = Arg->getAs<EnumType>())
Tag = EnumT;
else if (const RecordType *RecordT = Arg->getAs<RecordType>())
Tag = RecordT;
if (Tag && Tag->getDecl()->getDeclContext()->isFunctionOrMethod()) {
SourceRange SR = ArgInfo->getTypeLoc().getSourceRange();
return Diag(SR.getBegin(), diag::err_template_arg_local_type)
<< QualType(Tag, 0) << SR;
} else if (Tag && !Tag->getDecl()->getDeclName() &&
!Tag->getDecl()->getTypedefForAnonDecl()) {
Diag(SR.getBegin(), diag::err_template_arg_unnamed_type) << SR;
Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here);
return true;
} else if (Arg->isVariablyModifiedType()) {
Diag(SR.getBegin(), diag::err_variably_modified_template_arg)
<< Arg;
return true;
if (!LangOpts.CPlusPlus0x) {
const TagType *Tag = 0;
if (const EnumType *EnumT = Arg->getAs<EnumType>())
Tag = EnumT;
else if (const RecordType *RecordT = Arg->getAs<RecordType>())
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;
}

View File

@ -0,0 +1,20 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
// C++03 imposed restrictions in this paragraph that were lifted with 0x, so we
// just test that the example given now parses cleanly.
template <class T> class X { };
template <class T> void f(T t) { }
struct { } unnamed_obj;
void f() {
struct A { };
enum { e1 };
typedef struct { } B;
B b;
X<A> x1;
X<A*> x2;
X<B> x3;
f(e1);
f(unnamed_obj);
f(b);
}

View File

@ -0,0 +1,40 @@
// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -emit-llvm -o - | FileCheck %s
struct S {
enum { FOO = 42 };
enum { BAR = 42 };
};
template <typename T> struct X {
T value;
X(T t) : value(t) {}
// Again, two instantiations should be present.
int f() { return value; }
};
template <typename T> int f(T t) {
X<T> x(t);
return x.f();
}
void test() {
// Look for two instantiations, entirely internal to this TU, one for FOO's
// type and one for BAR's.
// CHECK: define internal i32 @"_Z1fIN1S3$_0EEiT_"(i32 %t)
(void)f(S::FOO);
// CHECK: define internal i32 @"_Z1fIN1S3$_1EEiT_"(i32 %t)
(void)f(S::BAR);
// Now check for the class template instantiations. Annoyingly, they are in
// reverse order.
//
// BAR's instantiation of X:
// CHECK: define internal i32 @"_ZN1XIN1S3$_1EE1fEv"(%struct.X* %this)
// CHECK: define internal void @"_ZN1XIN1S3$_1EEC2ES1_"(%struct.X* %this, i32 %t)
//
// FOO's instantiation of X:
// CHECK: define internal i32 @"_ZN1XIN1S3$_0EE1fEv"(%struct.X* %this)
// CHECK: define internal void @"_ZN1XIN1S3$_0EEC2ES1_"(%struct.X* %this, i32 %t)
}

View File

@ -24,11 +24,11 @@ A<ns::B> a8; // expected-error{{use of class template ns::B requires template ar
// [temp.arg.type]p2
void f() {
class X { };
A<X> * a = 0; // expected-error{{template argument uses local type 'X'}}
A<X> * a = 0; // expected-warning{{template argument uses local type 'X'}}
}
struct { int x; } Unnamed; // expected-note{{unnamed type used in template argument was declared here}}
A<__typeof__(Unnamed)> *a9; // expected-error{{template argument uses unnamed type}}
A<__typeof__(Unnamed)> *a9; // expected-warning{{template argument uses unnamed type}}
template<typename T, unsigned N>
struct Array {