forked from OSchip/llvm-project
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:
parent
baef18dffb
commit
997a719d5a
|
@ -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;
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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() }];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -180,3 +180,8 @@ namespace DependentTemplateName {
|
|||
getWithIdentifier<HasMember>();
|
||||
}
|
||||
}
|
||||
|
||||
namespace ClassTemplateCycle {
|
||||
extern T t;
|
||||
int k = M;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue