[cfe-commits] r100054 - in /cfe/trunk: include/clang/AST/Type.h lib/AST/Type.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplate.cpp lib/Sema/TreeTransform.h test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp test/SemaTemplate/instantiate-elab-type-specifier.cpp
Douglas Gregor
dgregor at apple.com
Wed Mar 31 15:19:08 PDT 2010
Author: dgregor
Date: Wed Mar 31 17:19:08 2010
New Revision: 100054
URL: http://llvm.org/viewvc/llvm-project?rev=100054&view=rev
Log:
Change the representation of dependent elaborated-type-specifiers
(such as "class T::foo") from an ElaboratedType of a TypenameType to a
DependentNameType, which more accurately models the underlying
concept.
Improve template instantiation for DependentNameType nodes that
represent nested-name-specifiers, by performing tag name lookup and
checking the resulting tag appropriately. Fixes PR5681.
There is still much testing and cleanup to do in this area.
Added:
cfe/trunk/test/SemaTemplate/instantiate-elab-type-specifier.cpp
Modified:
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/lib/AST/Type.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/TreeTransform.h
cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=100054&r1=100053&r2=100054&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Wed Mar 31 17:19:08 2010
@@ -894,6 +894,9 @@
bool isDependentType() const { return Dependent; }
bool isOverloadableType() const;
+ /// \brief Determine wither this type is a C++ elaborated-type-specifier.
+ bool isElaboratedTypeSpecifier() const;
+
/// hasPointerRepresentation - Whether this type is represented
/// natively as a pointer; this includes pointers, references, block
/// pointers, and Objective-C interface, qualified id, and qualified
Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=100054&r1=100053&r2=100054&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Wed Mar 31 17:19:08 2010
@@ -760,6 +760,27 @@
}
}
+bool Type::isElaboratedTypeSpecifier() const {
+ if (getTypeClass() == Elaborated)
+ return true;
+
+ if (const DependentNameType *Dependent = dyn_cast<DependentNameType>(this)) {
+ switch (Dependent->getKeyword()) {
+ case ETK_None:
+ case ETK_Typename:
+ return false;
+
+ case ETK_Class:
+ case ETK_Struct:
+ case ETK_Union:
+ case ETK_Enum:
+ return true;
+ }
+ }
+
+ return false;
+}
+
const char *Type::getTypeClassName() const {
switch (TC) {
default: assert(0 && "Type class not in TypeNodes.def!");
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=100054&r1=100053&r2=100054&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Mar 31 17:19:08 2010
@@ -5408,7 +5408,7 @@
//
// FIXME: handle "template <> friend class A<T>;", which
// is possibly well-formed? Who even knows?
- if (TempParams.size() && !isa<ElaboratedType>(T)) {
+ if (TempParams.size() && !T->isElaboratedTypeSpecifier()) {
Diag(Loc, diag::err_tagless_friend_type_template)
<< DS.getSourceRange();
return DeclPtrTy();
@@ -5420,7 +5420,7 @@
// * The class-key of the elaborated-type-specifier is required.
// This is one of the rare places in Clang where it's legitimate to
// ask about the "spelling" of the type.
- if (!getLangOptions().CPlusPlus0x && !isa<ElaboratedType>(T)) {
+ if (!getLangOptions().CPlusPlus0x && !T->isElaboratedTypeSpecifier()) {
// If we evaluated the type to a record type, suggest putting
// a tag in front.
if (const RecordType *RT = T->getAs<RecordType>()) {
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=100054&r1=100053&r2=100054&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Mar 31 17:19:08 2010
@@ -4915,14 +4915,15 @@
if (!NNS)
return true;
- QualType T = CheckTypenameType(NNS, *Name, SourceRange(TagLoc, NameLoc));
- if (T.isNull())
- return true;
-
- TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec);
- QualType ElabType = Context.getElaboratedType(T, TagKind);
-
- return ElabType.getAsOpaquePtr();
+ ElaboratedTypeKeyword Keyword;
+ switch (TagDecl::getTagKindForTypeSpec(TagSpec)) {
+ case TagDecl::TK_struct: Keyword = ETK_Struct; break;
+ case TagDecl::TK_class: Keyword = ETK_Class; break;
+ case TagDecl::TK_union: Keyword = ETK_Union; break;
+ case TagDecl::TK_enum: Keyword = ETK_Enum; break;
+ }
+
+ return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr();
}
Sema::TypeResult
Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=100054&r1=100053&r2=100054&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Wed Mar 31 17:19:08 2010
@@ -537,19 +537,21 @@
/// \brief Build a new typename type that refers to a template-id.
///
- /// By default, builds a new DependentNameType type from the nested-name-specifier
+ /// By default, builds a new DependentNameType type from the
+ /// nested-name-specifier
/// and the given type. Subclasses may override this routine to provide
/// different behavior.
QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS, QualType T) {
if (NNS->isDependent()) {
+ // If the name is still dependent, just build a new dependent name type.
CXXScopeSpec SS;
SS.setScopeRep(NNS);
if (!SemaRef.computeDeclContext(SS))
return SemaRef.Context.getDependentNameType(Keyword, NNS,
cast<TemplateSpecializationType>(T));
}
-
+
// FIXME: Handle elaborated-type-specifiers separately.
return SemaRef.Context.getQualifiedNameType(NNS, T);
}
@@ -563,8 +565,76 @@
NestedNameSpecifier *NNS,
const IdentifierInfo *Id,
SourceRange SR) {
- // FIXME: Handle elaborated-type-specifiers separately.
- return SemaRef.CheckTypenameType(NNS, *Id, SR);
+ CXXScopeSpec SS;
+ SS.setScopeRep(NNS);
+
+ if (NNS->isDependent()) {
+ // If the name is still dependent, just build a new dependent name type.
+ if (!SemaRef.computeDeclContext(SS))
+ return SemaRef.Context.getDependentNameType(Keyword, NNS, Id);
+ }
+
+ TagDecl::TagKind Kind = TagDecl::TK_enum;
+ switch (Keyword) {
+ case ETK_None:
+ // FIXME: Note the lack of the "typename" specifier!
+ // Fall through
+ case ETK_Typename:
+ return SemaRef.CheckTypenameType(NNS, *Id, SR);
+
+ case ETK_Class: Kind = TagDecl::TK_class; break;
+ case ETK_Struct: Kind = TagDecl::TK_struct; break;
+ case ETK_Union: Kind = TagDecl::TK_union; break;
+ case ETK_Enum: Kind = TagDecl::TK_enum; break;
+ }
+
+ // We had a dependent elaborated-type-specifier that as been transformed
+ // into a non-dependent elaborated-type-specifier. Find the tag we're
+ // referring to.
+ LookupResult Result(SemaRef, Id, SR.getEnd(), Sema::LookupTagName);
+ DeclContext *DC = SemaRef.computeDeclContext(SS, false);
+ if (!DC)
+ return QualType();
+
+ TagDecl *Tag = 0;
+ SemaRef.LookupQualifiedName(Result, DC);
+ switch (Result.getResultKind()) {
+ case LookupResult::NotFound:
+ case LookupResult::NotFoundInCurrentInstantiation:
+ break;
+
+ case LookupResult::Found:
+ Tag = Result.getAsSingle<TagDecl>();
+ break;
+
+ case LookupResult::FoundOverloaded:
+ case LookupResult::FoundUnresolvedValue:
+ llvm_unreachable("Tag lookup cannot find non-tags");
+ return QualType();
+
+ case LookupResult::Ambiguous:
+ // Let the LookupResult structure handle ambiguities.
+ return QualType();
+ }
+
+ if (!Tag) {
+ // FIXME: Crummy diagnostic
+ SemaRef.Diag(SR.getEnd(), diag::err_not_tag_in_scope)
+ << Id << SR;
+ return QualType();
+ }
+
+ // FIXME: Terrible location information
+ if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, SR.getEnd(), *Id)) {
+ SemaRef.Diag(SR.getBegin(), diag::err_use_with_wrong_tag) << Id;
+ SemaRef.Diag(Tag->getLocation(), diag::note_previous_use);
+ return QualType();
+ }
+
+ // Build the elaborated-type-specifier type.
+ QualType T = SemaRef.Context.getTypeDeclType(Tag);
+ T = SemaRef.Context.getQualifiedNameType(NNS, T);
+ return SemaRef.Context.getElaboratedType(T, Kind);
}
/// \brief Build a new nested-name-specifier given the prefix and an
Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp?rev=100054&r1=100053&r2=100054&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp Wed Mar 31 17:19:08 2010
@@ -25,8 +25,7 @@
};
template <> struct B<A> {
- // FIXME: the error here should be associated with the use at "void foo..."
- union Member { // expected-note 4 {{previous use is here}} expected-error {{tag type that does not match previous declaration}}
+ union Member { // expected-note 4 {{previous use is here}}
void* a;
};
};
@@ -52,7 +51,8 @@
void e4(enum B<A>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
template <class T> struct C {
- void foo(class B<T>::Member); // expected-error{{no type named 'Member' in 'B<int>'}}
+ void foo(class B<T>::Member); // expected-error{{'Member' does not name a tag member in the specified scope}} \
+ // expected-error{{use of 'Member' with tag type that does not match previous declaration}}
};
C<float> f1;
Added: cfe/trunk/test/SemaTemplate/instantiate-elab-type-specifier.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-elab-type-specifier.cpp?rev=100054&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-elab-type-specifier.cpp (added)
+++ cfe/trunk/test/SemaTemplate/instantiate-elab-type-specifier.cpp Wed Mar 31 17:19:08 2010
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// PR5681
+template <class T> struct Base {
+ struct foo {};
+ int foo;
+};
+
+template <class T> struct Derived : Base<T> {
+ typedef struct Base<T>::foo type;
+};
+
+template struct Derived<int>;
More information about the cfe-commits
mailing list