PR48434: Work around crashes due to deserialization cycles via typedefs.

Ensure that we can deserialize a TypedefType even while in the middle of
deserializing its TypedefDecl, by removing the need to look at the
TypedefDecl while constructing the TypedefType.

This fixes all the currently-known failures for PR48434, but it's not a
complete fix, because we can still trigger deserialization cycles, which
are not supposed to happen.
This commit is contained in:
Richard Smith 2020-12-09 12:04:03 -08:00
parent baef18dffb
commit 997a719d5a
7 changed files with 40 additions and 13 deletions

View File

@ -1430,7 +1430,7 @@ public:
/// Return the unique reference to the type for the specified
/// typedef-name decl.
QualType getTypedefType(const TypedefNameDecl *Decl,
QualType Canon = QualType()) const;
QualType Underlying = QualType()) const;
QualType getRecordType(const RecordDecl *Decl) const;

View File

@ -4362,10 +4362,11 @@ public:
class TypedefType : public Type {
TypedefNameDecl *Decl;
protected:
private:
friend class ASTContext; // ASTContext creates these.
TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType can);
TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType underlying,
QualType can);
public:
TypedefNameDecl *getDecl() const { return Decl; }

View File

@ -484,8 +484,12 @@ let Class = TagType in {
let Read = [{ node->isDependentType() }];
}
def : Property<"declaration", DeclRef> {
// Serializing a reference to the canonical declaration is apparently
// necessary to make module-merging work.
// We don't know which declaration was originally referenced here, and we
// cannot reference a declaration that follows the use (because that can
// introduce deserialization cycles), so conservatively generate a
// reference to the first declaration.
// FIXME: If this is a reference to a class template specialization, that
// can still introduce a deserialization cycle.
let Read = [{ node->getDecl()->getCanonicalDecl() }];
}
}

View File

@ -4449,15 +4449,15 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const {
/// getTypedefType - Return the unique reference to the type for the
/// specified typedef name decl.
QualType
ASTContext::getTypedefType(const TypedefNameDecl *Decl,
QualType Canonical) const {
QualType ASTContext::getTypedefType(const TypedefNameDecl *Decl,
QualType Underlying) const {
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
if (Canonical.isNull())
Canonical = getCanonicalType(Decl->getUnderlyingType());
if (Underlying.isNull())
Underlying = Decl->getUnderlyingType();
QualType Canonical = getCanonicalType(Underlying);
auto *newType = new (*this, TypeAlignment)
TypedefType(Type::Typedef, Decl, Canonical);
TypedefType(Type::Typedef, Decl, Underlying, Canonical);
Decl->TypeForDecl = newType;
Types.push_back(newType);
return QualType(newType, 0);

View File

@ -3369,8 +3369,9 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID,
getExtProtoInfo(), Ctx, isCanonicalUnqualified());
}
TypedefType::TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType can)
: Type(tc, can, D->getUnderlyingType()->getDependence()),
TypedefType::TypedefType(TypeClass tc, const TypedefNameDecl *D,
QualType underlying, QualType can)
: Type(tc, can, underlying->getDependence()),
Decl(const_cast<TypedefNameDecl *>(D)) {
assert(!isa<TypedefType>(can) && "Invalid canonical type");
}

View File

@ -180,3 +180,8 @@ namespace DependentTemplateName {
getWithIdentifier<HasMember>();
}
}
namespace ClassTemplateCycle {
extern T t;
int k = M;
}

View File

@ -456,3 +456,19 @@ namespace DependentTemplateName {
template <class T>
TakesClassTemplate<T::template Member> getWithIdentifier();
}
namespace ClassTemplateCycle {
// Create a cycle: the typedef T refers to A<0, 8>, whose template argument
// list refers back to T.
template<int, int> struct A;
using T = A<0, sizeof(void*)>;
template<int N> struct A<N, sizeof(T*)> {};
T t;
// Create a cycle: the variable M refers to A<1, 1>, whose template argument
// list list refers back to M.
template<int, int> struct A;
const decltype(sizeof(A<1, 1>*)) M = 1;
template<int N> struct A<N, M> {};
A<1, 1> u;
}