Improve source-location information for C++ conversion functions, by

copying the type location information from the conversion-type-id into
the type location information for the function type. Do something
similar for constructors and destructors, by giving their "void"
return type source-location information.

In all of these cases, we previously left this type-source information
uninitialized, which led to various unfortunate crashes.

We still aren't tracking good source-location information for the
actual names. That's PR6357.

John, please check my sanity on this.

llvm-svn: 101088
This commit is contained in:
Douglas Gregor 2010-04-12 23:19:01 +00:00
parent ebbd05f8ce
commit 5c0066f1cf
3 changed files with 67 additions and 6 deletions

View File

@ -704,7 +704,8 @@ public:
QualType GetTypeForDeclarator(Declarator &D, Scope *S,
TypeSourceInfo **TInfo = 0,
TagDecl **OwnedDecl = 0);
TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T);
TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
TypeSourceInfo *ReturnTypeInfo);
/// \brief Create a LocInfoType to hold the given QualType and TypeSourceInfo.
QualType CreateLocInfoType(QualType T, TypeSourceInfo *TInfo);
DeclarationName GetNameForDeclarator(Declarator &D);

View File

@ -922,7 +922,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// Determine the type of the declarator. Not all forms of declarator
// have a type.
QualType T;
TypeSourceInfo *ReturnTypeInfo = 0;
llvm::SmallVector<DelayedAttribute,4> FnAttrsFromDeclSpec;
switch (D.getName().getKind()) {
@ -948,12 +949,20 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// Constructors and destructors don't have return types. Use
// "void" instead.
T = Context.VoidTy;
// FIXME: Keep track of source location information within the constructor
// or destructor name.
if (TInfo)
ReturnTypeInfo = Context.getTrivialTypeSourceInfo(T,
D.getName().StartLocation);
break;
case UnqualifiedId::IK_ConversionFunctionId:
// The result type of a conversion function is the type that it
// converts to.
T = GetTypeFromParser(D.getName().ConversionFunctionId);
// FIXME: Keep track of the location of the 'operator' keyword?
T = GetTypeFromParser(D.getName().ConversionFunctionId,
TInfo? &ReturnTypeInfo : 0);
break;
}
@ -1356,7 +1365,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (D.isInvalidType())
*TInfo = 0;
else
*TInfo = GetTypeSourceInfoForDeclarator(D, T);
*TInfo = GetTypeSourceInfoForDeclarator(D, T, ReturnTypeInfo);
}
return T;
@ -1541,8 +1550,14 @@ namespace {
/// \brief Create and instantiate a TypeSourceInfo with type source information.
///
/// \param T QualType referring to the type as written in source code.
///
/// \param ReturnTypeInfo For declarators whose return type does not show
/// up in the normal place in the declaration specifiers (such as a C++
/// conversion function), this pointer will refer to a type source information
/// for that return type.
TypeSourceInfo *
Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T) {
Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
TypeSourceInfo *ReturnTypeInfo) {
TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T);
UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc();
@ -1552,7 +1567,18 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T) {
}
TypeSpecLocFiller(D.getDeclSpec()).Visit(CurrTL);
// We have source information for the return type that was not in the
// declaration specifiers; copy that information into the current type
// location so that it will be retained. This occurs, for example, with
// a C++ conversion function, where the return type occurs within the
// declarator-id rather than in the declaration specifiers.
if (ReturnTypeInfo && D.getDeclSpec().getTypeSpecType() == TST_unspecified) {
TypeLoc TL = ReturnTypeInfo->getTypeLoc();
assert(TL.getFullDataSize() == CurrTL.getFullDataSize());
memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize());
}
return TInfo;
}

View File

@ -131,3 +131,37 @@ private:
A1 f() {
return "Hello"; // expected-error{{invokes deleted copy constructor}}
}
namespace source_locations {
template<typename T>
struct sneaky_int {
typedef int type;
};
template<typename T, typename U>
struct A { };
template<typename T>
struct A<T, T> : A<T, int> { };
struct E {
template<typename T>
operator A<T, typename sneaky_int<T>::type>&() const; // expected-note{{candidate function}}
};
void f() {
A<float, float> &af = E(); // expected-error{{no viable conversion}}
A<float, int> &af2 = E();
const A<float, int> &caf2 = E();
}
// Check
template<typename T>
struct E2 {
operator T
* // expected-error{{pointer to a reference}}
() const;
};
E2<int&> e2i; // expected-note{{in instantiation}}
}