Report accurate source-location information when rebuilding types during

template instantiation.

llvm-svn: 85545
This commit is contained in:
John McCall 2009-10-30 00:06:24 +00:00
parent f3eb5ec2c0
commit 70dd5f6574
3 changed files with 242 additions and 80 deletions

View File

@ -775,6 +775,10 @@ public:
getLocalData()->RBracketLoc = Loc;
}
SourceRange getBracketsRange() const {
return SourceRange(getLBracketLoc(), getRBracketLoc());
}
Expr *getSizeExpr() const {
return getLocalData()->Size;
}

View File

@ -310,6 +310,8 @@ public:
QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T);
#include "clang/AST/TypeLocNodes.def"
QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL);
QualType
TransformTemplateSpecializationType(const TemplateSpecializationType *T,
QualType ObjectType);
@ -332,35 +334,37 @@ public:
///
/// By default, performs semantic analysis when building the pointer type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildPointerType(QualType PointeeType);
QualType RebuildPointerType(QualType PointeeType, SourceLocation Sigil);
/// \brief Build a new block pointer type given its pointee type.
///
/// By default, performs semantic analysis when building the block pointer
/// type. Subclasses may override this routine to provide different behavior.
QualType RebuildBlockPointerType(QualType PointeeType);
QualType RebuildBlockPointerType(QualType PointeeType, SourceLocation Sigil);
/// \brief Build a new lvalue reference type given the type it references.
/// \brief Build a new reference type given the type it references.
///
/// By default, performs semantic analysis when building the lvalue reference
/// type. Subclasses may override this routine to provide different behavior.
QualType RebuildLValueReferenceType(QualType ReferentType);
/// \brief Build a new rvalue reference type given the type it references.
/// By default, performs semantic analysis when building the
/// reference type. Subclasses may override this routine to provide
/// different behavior.
///
/// By default, performs semantic analysis when building the rvalue reference
/// type. Subclasses may override this routine to provide different behavior.
QualType RebuildRValueReferenceType(QualType ReferentType);
/// \param LValue whether the type was written with an lvalue sigil
/// or an rvalue sigil.
QualType RebuildReferenceType(QualType ReferentType,
bool LValue,
SourceLocation Sigil);
/// \brief Build a new member pointer type given the pointee type and the
/// class type it refers into.
///
/// By default, performs semantic analysis when building the member pointer
/// type. Subclasses may override this routine to provide different behavior.
QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType);
QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType,
SourceLocation Sigil);
/// \brief Build a new Objective C object pointer type.
QualType RebuildObjCObjectPointerType(QualType PointeeType);
QualType RebuildObjCObjectPointerType(QualType PointeeType,
SourceLocation Sigil);
/// \brief Build a new array type given the element type, size
/// modifier, size of the array (if known), size expression, and index type
@ -384,7 +388,8 @@ public:
QualType RebuildConstantArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
const llvm::APInt &Size,
unsigned IndexTypeQuals);
unsigned IndexTypeQuals,
SourceRange BracketsRange);
/// \brief Build a new incomplete array type given the element type, size
/// modifier, and index type qualifiers.
@ -393,7 +398,8 @@ public:
/// Subclasses may override this routine to provide different behavior.
QualType RebuildIncompleteArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
unsigned IndexTypeQuals);
unsigned IndexTypeQuals,
SourceRange BracketsRange);
/// \brief Build a new variable-length array type given the element type,
/// size modifier, size expression, and index type qualifiers.
@ -2124,7 +2130,8 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) {
QualType Result = TL.getType(); \
if (getDerived().AlwaysRebuild() || \
PointeeType != TL.getPointeeLoc().getType()) { \
Result = getDerived().Rebuild##TypeClass(PointeeType); \
Result = getDerived().Rebuild##TypeClass(PointeeType, \
TL.getSigilLoc()); \
if (Result.isNull()) \
return QualType(); \
} \
@ -2135,35 +2142,6 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) {
return Result; \
} while(0)
// Reference collapsing forces us to transform reference types
// differently from the other pointer-like types.
#define TransformReferenceType(TypeClass) do { \
QualType PointeeType \
= getDerived().TransformType(TLB, TL.getPointeeLoc()); \
if (PointeeType.isNull()) \
return QualType(); \
\
QualType Result = TL.getType(); \
if (getDerived().AlwaysRebuild() || \
PointeeType != TL.getPointeeLoc().getType()) { \
Result = getDerived().Rebuild##TypeClass(PointeeType); \
if (Result.isNull()) \
return QualType(); \
} \
\
/* Workaround: rebuild doesn't always change the type */ \
/* FIXME: avoid losing this location information. */ \
if (Result == PointeeType) \
return Result; \
ReferenceTypeLoc NewTL; \
if (isa<LValueReferenceType>(Result)) \
NewTL = TLB.push<LValueReferenceTypeLoc>(Result); \
else \
NewTL = TLB.push<RValueReferenceTypeLoc>(Result); \
NewTL.setSigilLoc(TL.getSigilLoc()); \
return Result; \
} while (0)
template<typename Derived>
QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB,
BuiltinTypeLoc T) {
@ -2197,18 +2175,54 @@ TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB,
TransformPointerLikeType(BlockPointerType);
}
/// Transforms a reference type. Note that somewhat paradoxically we
/// don't care whether the type itself is an l-value type or an r-value
/// type; we only care if the type was *written* as an l-value type
/// or an r-value type.
template<typename Derived>
QualType
TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB,
ReferenceTypeLoc TL) {
const ReferenceType *T = TL.getTypePtr();
// Note that this works with the pointee-as-written.
QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc());
if (PointeeType.isNull())
return QualType();
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
PointeeType != T->getPointeeTypeAsWritten()) {
Result = getDerived().RebuildReferenceType(PointeeType,
T->isSpelledAsLValue(),
TL.getSigilLoc());
if (Result.isNull())
return QualType();
}
// r-value references can be rebuilt as l-value references.
ReferenceTypeLoc NewTL;
if (isa<LValueReferenceType>(Result))
NewTL = TLB.push<LValueReferenceTypeLoc>(Result);
else
NewTL = TLB.push<RValueReferenceTypeLoc>(Result);
NewTL.setSigilLoc(TL.getSigilLoc());
return Result;
}
template<typename Derived>
QualType
TreeTransform<Derived>::TransformLValueReferenceType(TypeLocBuilder &TLB,
LValueReferenceTypeLoc TL) {
TransformReferenceType(LValueReferenceType);
return TransformReferenceType(TLB, TL);
}
template<typename Derived>
QualType
TreeTransform<Derived>::TransformRValueReferenceType(TypeLocBuilder &TLB,
RValueReferenceTypeLoc TL) {
TransformReferenceType(RValueReferenceType);
return TransformReferenceType(TLB, TL);
}
template<typename Derived>
@ -2231,7 +2245,8 @@ TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB,
if (getDerived().AlwaysRebuild() ||
PointeeType != T->getPointeeType() ||
ClassType != QualType(T->getClass(), 0)) {
Result = getDerived().RebuildMemberPointerType(PointeeType, ClassType);
Result = getDerived().RebuildMemberPointerType(PointeeType, ClassType,
TL.getStarLoc());
if (Result.isNull())
return QualType();
}
@ -2257,7 +2272,8 @@ TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB,
Result = getDerived().RebuildConstantArrayType(ElementType,
T->getSizeModifier(),
T->getSize(),
T->getIndexTypeCVRQualifiers());
T->getIndexTypeCVRQualifiers(),
TL.getBracketsRange());
if (Result.isNull())
return QualType();
}
@ -2290,7 +2306,8 @@ QualType TreeTransform<Derived>::TransformIncompleteArrayType(
ElementType != T->getElementType()) {
Result = getDerived().RebuildIncompleteArrayType(ElementType,
T->getSizeModifier(),
T->getIndexTypeCVRQualifiers());
T->getIndexTypeCVRQualifiers(),
TL.getBracketsRange());
if (Result.isNull())
return QualType();
}
@ -2330,7 +2347,7 @@ TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB,
T->getSizeModifier(),
move(SizeResult),
T->getIndexTypeCVRQualifiers(),
T->getBracketsRange());
TL.getBracketsRange());
if (Result.isNull())
return QualType();
}
@ -2371,7 +2388,7 @@ TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB,
T->getSizeModifier(),
move(SizeResult),
T->getIndexTypeCVRQualifiers(),
T->getBracketsRange());
TL.getBracketsRange());
if (Result.isNull())
return QualType();
}
@ -4907,48 +4924,42 @@ TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) {
//===----------------------------------------------------------------------===//
template<typename Derived>
QualType TreeTransform<Derived>::RebuildPointerType(QualType PointeeType) {
return SemaRef.BuildPointerType(PointeeType, Qualifiers(),
getDerived().getBaseLocation(),
QualType TreeTransform<Derived>::RebuildPointerType(QualType PointeeType,
SourceLocation Star) {
return SemaRef.BuildPointerType(PointeeType, Qualifiers(), Star,
getDerived().getBaseEntity());
}
template<typename Derived>
QualType TreeTransform<Derived>::RebuildBlockPointerType(QualType PointeeType) {
return SemaRef.BuildBlockPointerType(PointeeType, Qualifiers(),
getDerived().getBaseLocation(),
QualType TreeTransform<Derived>::RebuildBlockPointerType(QualType PointeeType,
SourceLocation Star) {
return SemaRef.BuildBlockPointerType(PointeeType, Qualifiers(), Star,
getDerived().getBaseEntity());
}
template<typename Derived>
QualType
TreeTransform<Derived>::RebuildLValueReferenceType(QualType ReferentType) {
return SemaRef.BuildReferenceType(ReferentType, true, Qualifiers(),
getDerived().getBaseLocation(),
getDerived().getBaseEntity());
TreeTransform<Derived>::RebuildReferenceType(QualType ReferentType,
bool WrittenAsLValue,
SourceLocation Sigil) {
return SemaRef.BuildReferenceType(ReferentType, WrittenAsLValue, Qualifiers(),
Sigil, getDerived().getBaseEntity());
}
template<typename Derived>
QualType
TreeTransform<Derived>::RebuildRValueReferenceType(QualType ReferentType) {
return SemaRef.BuildReferenceType(ReferentType, false, Qualifiers(),
getDerived().getBaseLocation(),
getDerived().getBaseEntity());
}
template<typename Derived>
QualType TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType,
QualType ClassType) {
TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType,
QualType ClassType,
SourceLocation Sigil) {
return SemaRef.BuildMemberPointerType(PointeeType, ClassType, Qualifiers(),
getDerived().getBaseLocation(),
getDerived().getBaseEntity());
Sigil, getDerived().getBaseEntity());
}
template<typename Derived>
QualType
TreeTransform<Derived>::RebuildObjCObjectPointerType(QualType PointeeType) {
return SemaRef.BuildPointerType(PointeeType, Qualifiers(),
getDerived().getBaseLocation(),
TreeTransform<Derived>::RebuildObjCObjectPointerType(QualType PointeeType,
SourceLocation Sigil) {
return SemaRef.BuildPointerType(PointeeType, Qualifiers(), Sigil,
getDerived().getBaseEntity());
}
@ -4992,18 +5003,20 @@ QualType
TreeTransform<Derived>::RebuildConstantArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
const llvm::APInt &Size,
unsigned IndexTypeQuals) {
unsigned IndexTypeQuals,
SourceRange BracketsRange) {
return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, 0,
IndexTypeQuals, SourceRange());
IndexTypeQuals, BracketsRange);
}
template<typename Derived>
QualType
TreeTransform<Derived>::RebuildIncompleteArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
unsigned IndexTypeQuals) {
unsigned IndexTypeQuals,
SourceRange BracketsRange) {
return getDerived().RebuildArrayType(ElementType, SizeMod, 0, 0,
IndexTypeQuals, SourceRange());
IndexTypeQuals, BracketsRange);
}
template<typename Derived>

View File

@ -0,0 +1,145 @@
// RUN: clang-cc -fsyntax-only -verify %s
// C++ [dcl.ref]p5:
// There shall be no references to references, no arrays of
// references, and no pointers to references.
// The crazy formatting in here is to enforce the exact report locations.
typedef int &intref;
typedef intref &intrefref;
template <class T> class RefMem {
T
&
member;
};
struct RefRef {
int
&
& // expected-error {{declared as a reference to a reference}}
refref0;
intref
&
refref1; // collapses
intrefref
&
refref2; // collapses
RefMem
<
int
&
>
refref3; // collapses
};
template <class T> class PtrMem {
T
* // expected-error {{declared as a pointer to a reference}}
member;
};
struct RefPtr {
typedef
int
&
* // expected-error {{declared as a pointer to a reference}}
intrefptr;
typedef
intref
* // expected-error {{declared as a pointer to a reference}}
intrefptr2;
int
&
* // expected-error {{declared as a pointer to a reference}}
refptr0;
intref
* // expected-error {{declared as a pointer to a reference}}
refptr1;
PtrMem
<
int
&
>
refptr2; // expected-note {{in instantiation}}
};
template <class T> class ArrMem {
T
member
[ // expected-error {{declared as array of references}}
10
];
};
template <class T, unsigned N> class DepArrMem {
T
member
[ // expected-error {{declared as array of references}}
N
];
};
struct RefArr {
typedef
int
&
intrefarr
[ // expected-error {{declared as array of references}}
2
];
typedef
intref
intrefarr
[ // expected-error {{declared as array of references}}
2
];
int
&
refarr0
[ // expected-error {{declared as array of references}}
2
];
intref
refarr1
[ // expected-error {{declared as array of references}}
2
];
ArrMem
<
int
&
>
refarr2; // expected-note {{in instantiation}}
DepArrMem
<
int
&,
10
>
refarr3; // expected-note {{in instantiation}}
};
// The declaration of a reference shall contain an initializer
// (8.5.3) except when the declaration contains an explicit extern
// specifier (7.1.1), is a class member (9.2) declaration within a
// class definition, or is the declaration of a parameter or a
// return type (8.3.5); see 3.1. A reference shall be initialized to
// refer to a valid object or function. [ Note: in particular, a
// null reference cannot exist in a well-defined program, because
// the only way to create such a reference would be to bind it to
// the "object" obtained by dereferencing a null pointer, which
// causes undefined behavior. As described in 9.6, a reference
// cannot be bound directly to a bit-field.