forked from OSchip/llvm-project
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:
parent
2a9de4d828
commit
9bb67f4d1a
|
@ -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">;
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue