diff options
author | Chandler Carruth <chandlerc@gmail.com> | 2010-09-03 21:12:34 +0000 |
---|---|---|
committer | Chandler Carruth <chandlerc@gmail.com> | 2010-09-03 21:12:34 +0000 |
commit | 9bb67f4d1ab7afb7840aaee490e6213e83ebca85 (patch) | |
tree | 9f2b9fb2c2033a1b95c2b167731922eac4b0281e | |
parent | 2a9de4d8288e2709becfba613c73bc295cb00f56 (diff) | |
download | llvm-9bb67f4d1ab7afb7840aaee490e6213e83ebca85.zip llvm-9bb67f4d1ab7afb7840aaee490e6213e83ebca85.tar.gz llvm-9bb67f4d1ab7afb7840aaee490e6213e83ebca85.tar.bz2 |
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
-rw-r--r-- | clang/include/clang/Basic/DiagnosticGroups.td | 2 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 7 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 44 | ||||
-rw-r--r-- | clang/test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp | 20 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/template-anonymous-types.cpp | 40 | ||||
-rw-r--r-- | clang/test/SemaTemplate/temp_arg_type.cpp | 4 |
6 files changed, 91 insertions, 26 deletions
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index f6fb79d..d4b7f1f 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -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">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 58e4dd4..a25b2a3 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 3c6ecaa..0fc8392 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -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; } diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp new file mode 100644 index 0000000..6f6286f --- /dev/null +++ b/clang/test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp @@ -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); +} diff --git a/clang/test/CodeGenCXX/template-anonymous-types.cpp b/clang/test/CodeGenCXX/template-anonymous-types.cpp new file mode 100644 index 0000000..0b219ff --- /dev/null +++ b/clang/test/CodeGenCXX/template-anonymous-types.cpp @@ -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) +} diff --git a/clang/test/SemaTemplate/temp_arg_type.cpp b/clang/test/SemaTemplate/temp_arg_type.cpp index 3876c25..3970942 100644 --- a/clang/test/SemaTemplate/temp_arg_type.cpp +++ b/clang/test/SemaTemplate/temp_arg_type.cpp @@ -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 { |