summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2010-09-03 21:12:34 +0000
committerChandler Carruth <chandlerc@gmail.com>2010-09-03 21:12:34 +0000
commit17fb855280be411389361f1c79753e0013c4187c (patch)
treefbf84b9e0fe9e6f83e95048bffba49c5a7993097
parent9c20fa9d46645480872f239a2fc631996ba7dc23 (diff)
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
-rw-r--r--include/clang/Basic/DiagnosticGroups.td2
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td7
-rw-r--r--lib/Sema/SemaTemplate.cpp44
-rw-r--r--test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp20
-rw-r--r--test/CodeGenCXX/template-anonymous-types.cpp40
-rw-r--r--test/SemaTemplate/temp_arg_type.cpp4
6 files changed, 91 insertions, 26 deletions
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<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/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<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/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 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/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 <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/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<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 {