From 17fb855280be411389361f1c79753e0013c4187c Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Fri, 3 Sep 2010 21:12:34 +0000 Subject: 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@113011 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticGroups.td | 2 ++ include/clang/Basic/DiagnosticSemaKinds.td | 7 ++-- lib/Sema/SemaTemplate.cpp | 44 ++++++++++++----------- test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp | 20 +++++++++++ test/CodeGenCXX/template-anonymous-types.cpp | 40 +++++++++++++++++++++ test/SemaTemplate/temp_arg_type.cpp | 4 +-- 6 files changed, 91 insertions(+), 26 deletions(-) create mode 100644 test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp create mode 100644 test/CodeGenCXX/template-anonymous-types.cpp diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index f6fb79d03c..d4b7f1f557 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/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/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 58e4dd4121..a25b2a341f 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/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; +def ext_template_arg_unnamed_type : ExtWarn< + "template argument uses unnamed type">, InGroup; 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/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 3c6ecaa53e..0fc83927b7 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/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()) - Tag = EnumT; - else if (const RecordType *RecordT = Arg->getAs()) - 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()) + Tag = EnumT; + else if (const RecordType *RecordT = Arg->getAs()) + 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/test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp b/test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp new file mode 100644 index 0000000000..6f6286f710 --- /dev/null +++ b/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 X { }; +template void f(T t) { } +struct { } unnamed_obj; +void f() { + struct A { }; + enum { e1 }; + typedef struct { } B; + B b; + X x1; + X x2; + X x3; + f(e1); + f(unnamed_obj); + f(b); +} diff --git a/test/CodeGenCXX/template-anonymous-types.cpp b/test/CodeGenCXX/template-anonymous-types.cpp new file mode 100644 index 0000000000..0b219ffc12 --- /dev/null +++ b/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 struct X { + T value; + + X(T t) : value(t) {} + + // Again, two instantiations should be present. + int f() { return value; } +}; + +template int f(T t) { + X 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/test/SemaTemplate/temp_arg_type.cpp b/test/SemaTemplate/temp_arg_type.cpp index 3876c25645..397094218a 100644 --- a/test/SemaTemplate/temp_arg_type.cpp +++ b/test/SemaTemplate/temp_arg_type.cpp @@ -24,11 +24,11 @@ A a8; // expected-error{{use of class template ns::B requires template ar // [temp.arg.type]p2 void f() { class X { }; - A * a = 0; // expected-error{{template argument uses local type 'X'}} + A * 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 struct Array { -- cgit v1.2.3