[cfe-commits] r78316 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplate.cpp lib/Sema/TreeTransform.h test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp
Douglas Gregor
dgregor at apple.com
Thu Aug 6 09:20:37 PDT 2009
Author: dgregor
Date: Thu Aug 6 11:20:37 2009
New Revision: 78316
URL: http://llvm.org/viewvc/llvm-project?rev=78316&view=rev
Log:
When we encounter a dependent type that was parsed before we know that
we were going to enter into the scope of a class template or class
template partial specialization, rebuild that type so that it can
refer to members of the current instantiation, as in code like
template<typename T>
struct X {
typedef T* pointer;
pointer data();
};
template<typename T>
typename X<T>::pointer X<T>::data() { ... }
Without rebuilding the return type of this out-of-line definition, the
canonical return type of the out-of-line definition (a TypenameType)
will not match the canonical return type of the declaration (the
canonical type of T*).
Modified:
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/TreeTransform.h
cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=78316&r1=78315&r2=78316&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Aug 6 11:20:37 2009
@@ -2321,6 +2321,9 @@
const IdentifierInfo &II,
SourceRange Range);
+ QualType RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc,
+ DeclarationName Name);
+
/// \brief Describes the result of template argument deduction.
///
/// The TemplateDeductionResult enumeration describes the result of
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=78316&r1=78315&r2=78316&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Aug 6 11:20:37 2009
@@ -1628,6 +1628,30 @@
(S->getFlags() & Scope::TemplateParamScope) != 0)
S = S->getParent();
+ // If this is an out-of-line definition of a member of a class template
+ // or class template partial specialization, we may need to rebuild the
+ // type specifier in the declarator. See RebuildTypeInCurrentInstantiation()
+ // for more information.
+ // FIXME: cope with decltype(expr) and typeof(expr) once the rebuilder can
+ // handle expressions properly.
+ DeclSpec &DS = const_cast<DeclSpec&>(D.getDeclSpec());
+ if (D.getCXXScopeSpec().isSet() && !D.getCXXScopeSpec().isInvalid() &&
+ isDependentScopeSpecifier(D.getCXXScopeSpec()) &&
+ (DS.getTypeSpecType() == DeclSpec::TST_typename ||
+ DS.getTypeSpecType() == DeclSpec::TST_typeofType ||
+ DS.getTypeSpecType() == DeclSpec::TST_typeofExpr ||
+ DS.getTypeSpecType() == DeclSpec::TST_decltype)) {
+ if (DeclContext *DC = computeDeclContext(D.getCXXScopeSpec(), true)) {
+ QualType T = QualType::getFromOpaquePtr(DS.getTypeRep());
+ EnterDeclaratorContext(S, DC);
+ T = RebuildTypeInCurrentInstantiation(T, D.getIdentifierLoc(), Name);
+ ExitDeclaratorContext(S);
+ if (T.isNull())
+ return DeclPtrTy();
+ DS.UpdateTypeRep(T.getAsOpaquePtr());
+ }
+ }
+
DeclContext *DC;
NamedDecl *PrevDecl;
NamedDecl *New;
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=78316&r1=78315&r2=78316&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Aug 6 11:20:37 2009
@@ -10,12 +10,14 @@
//===----------------------------------------------------------------------===/
#include "Sema.h"
+#include "TreeTransform.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Basic/LangOptions.h"
+#include "llvm/Support/Compiler.h"
using namespace clang;
@@ -3057,3 +3059,120 @@
<< Name;
return QualType();
}
+
+namespace {
+ // See Sema::RebuildTypeInCurrentInstantiation
+ class VISIBILITY_HIDDEN CurrentInstantiationRebuilder
+ : public TreeTransform<CurrentInstantiationRebuilder>
+ {
+ SourceLocation Loc;
+ DeclarationName Entity;
+
+ public:
+ CurrentInstantiationRebuilder(Sema &SemaRef,
+ SourceLocation Loc,
+ DeclarationName Entity)
+ : TreeTransform<CurrentInstantiationRebuilder>(SemaRef),
+ Loc(Loc), Entity(Entity) { }
+
+ /// \brief Determine whether the given type \p T has already been
+ /// transformed.
+ ///
+ /// For the purposes of type reconstruction, a type has already been
+ /// transformed if it is NULL or if it is not dependent.
+ bool AlreadyTransformed(QualType T) {
+ return T.isNull() || !T->isDependentType();
+ }
+
+ /// \brief Returns the location of the entity whose type is being
+ /// rebuilt.
+ SourceLocation getBaseLocation() { return Loc; }
+
+ /// \brief Returns the name of the entity whose type is being rebuilt.
+ DeclarationName getBaseEntity() { return Entity; }
+
+ /// \brief Transforms an expression by returning the expression itself
+ /// (an identity function).
+ ///
+ /// FIXME: This is completely unsafe; we will need to actually clone the
+ /// expressions.
+ Sema::OwningExprResult TransformExpr(Expr *E) {
+ return getSema().Owned(E);
+ }
+
+ /// \brief Transforms a typename type by determining whether the type now
+ /// refers to a member of the current instantiation, and then
+ /// type-checking and building a QualifiedNameType (when possible).
+ QualType TransformTypenameType(const TypenameType *T);
+ };
+}
+
+QualType
+CurrentInstantiationRebuilder::TransformTypenameType(const TypenameType *T) {
+ NestedNameSpecifier *NNS
+ = TransformNestedNameSpecifier(T->getQualifier(),
+ /*FIXME:*/SourceRange(getBaseLocation()));
+ if (!NNS)
+ return QualType();
+
+ // If the nested-name-specifier did not change, and we cannot compute the
+ // context corresponding to the nested-name-specifier, then this
+ // typename type will not change; exit early.
+ CXXScopeSpec SS;
+ SS.setRange(SourceRange(getBaseLocation()));
+ SS.setScopeRep(NNS);
+ if (NNS == T->getQualifier() && getSema().computeDeclContext(SS) == 0)
+ return QualType(T, 0);
+
+ // Rebuild the typename type, which will probably turn into a
+ // QualifiedNameType.
+ if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) {
+ QualType NewTemplateId
+ = TransformType(QualType(TemplateId, 0));
+ if (NewTemplateId.isNull())
+ return QualType();
+
+ if (NNS == T->getQualifier() &&
+ NewTemplateId == QualType(TemplateId, 0))
+ return QualType(T, 0);
+
+ return getDerived().RebuildTypenameType(NNS, NewTemplateId);
+ }
+
+ return getDerived().RebuildTypenameType(NNS, T->getIdentifier());
+}
+
+/// \brief Rebuilds a type within the context of the current instantiation.
+///
+/// The type \p T is part of the type of an out-of-line member definition of
+/// a class template (or class template partial specialization) that was parsed
+/// and constructed before we entered the scope of the class template (or
+/// partial specialization thereof). This routine will rebuild that type now
+/// that we have entered the declarator's scope, which may produce different
+/// canonical types, e.g.,
+///
+/// \code
+/// template<typename T>
+/// struct X {
+/// typedef T* pointer;
+/// pointer data();
+/// };
+///
+/// template<typename T>
+/// typename X<T>::pointer X<T>::data() { ... }
+/// \endcode
+///
+/// Here, the type "typename X<T>::pointer" will be created as a TypenameType,
+/// since we do not know that we can look into X<T> when we parsed the type.
+/// This function will rebuild the type, performing the lookup of "pointer"
+/// in X<T> and returning a QualifiedNameType whose canonical type is the same
+/// as the canonical type of T*, allowing the return types of the out-of-line
+/// definition and the declaration to match.
+QualType Sema::RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc,
+ DeclarationName Name) {
+ if (T.isNull() || !T->isDependentType())
+ return T;
+
+ CurrentInstantiationRebuilder Rebuilder(*this, Loc, Name);
+ return Rebuilder.TransformType(T);
+}
\ No newline at end of file
Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=78316&r1=78315&r2=78316&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Thu Aug 6 11:20:37 2009
@@ -1177,7 +1177,7 @@
QualType TreeTransform<Derived>::TransformTypenameType(const TypenameType *T) {
NestedNameSpecifier *NNS
= getDerived().TransformNestedNameSpecifier(T->getQualifier(),
- SourceRange(getDerived().getBaseLocation()));
+ SourceRange(/*FIXME:*/getDerived().getBaseLocation()));
if (!NNS)
return QualType();
Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp?rev=78316&r1=78315&r2=78316&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp Thu Aug 6 11:20:37 2009
@@ -1,5 +1,4 @@
// RUN: clang-cc -fsyntax-only -verify %s
-// XFAIL
template<typename T> struct X1 { };
More information about the cfe-commits
mailing list