Skip to content

Commit 997a719

Browse files
committed
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.
1 parent baef18d commit 997a719

File tree

7 files changed

+40
-13
lines changed

7 files changed

+40
-13
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1430,7 +1430,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
14301430
/// Return the unique reference to the type for the specified
14311431
/// typedef-name decl.
14321432
QualType getTypedefType(const TypedefNameDecl *Decl,
1433-
QualType Canon = QualType()) const;
1433+
QualType Underlying = QualType()) const;
14341434

14351435
QualType getRecordType(const RecordDecl *Decl) const;
14361436

clang/include/clang/AST/Type.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4362,10 +4362,11 @@ class UnresolvedUsingType : public Type {
43624362
class TypedefType : public Type {
43634363
TypedefNameDecl *Decl;
43644364

4365-
protected:
4365+
private:
43664366
friend class ASTContext; // ASTContext creates these.
43674367

4368-
TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType can);
4368+
TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType underlying,
4369+
QualType can);
43694370

43704371
public:
43714372
TypedefNameDecl *getDecl() const { return Decl; }

clang/include/clang/AST/TypeProperties.td

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,8 +484,12 @@ let Class = TagType in {
484484
let Read = [{ node->isDependentType() }];
485485
}
486486
def : Property<"declaration", DeclRef> {
487-
// Serializing a reference to the canonical declaration is apparently
488-
// necessary to make module-merging work.
487+
// We don't know which declaration was originally referenced here, and we
488+
// cannot reference a declaration that follows the use (because that can
489+
// introduce deserialization cycles), so conservatively generate a
490+
// reference to the first declaration.
491+
// FIXME: If this is a reference to a class template specialization, that
492+
// can still introduce a deserialization cycle.
489493
let Read = [{ node->getDecl()->getCanonicalDecl() }];
490494
}
491495
}

clang/lib/AST/ASTContext.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4449,15 +4449,15 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const {
44494449

44504450
/// getTypedefType - Return the unique reference to the type for the
44514451
/// specified typedef name decl.
4452-
QualType
4453-
ASTContext::getTypedefType(const TypedefNameDecl *Decl,
4454-
QualType Canonical) const {
4452+
QualType ASTContext::getTypedefType(const TypedefNameDecl *Decl,
4453+
QualType Underlying) const {
44554454
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
44564455

4457-
if (Canonical.isNull())
4458-
Canonical = getCanonicalType(Decl->getUnderlyingType());
4456+
if (Underlying.isNull())
4457+
Underlying = Decl->getUnderlyingType();
4458+
QualType Canonical = getCanonicalType(Underlying);
44594459
auto *newType = new (*this, TypeAlignment)
4460-
TypedefType(Type::Typedef, Decl, Canonical);
4460+
TypedefType(Type::Typedef, Decl, Underlying, Canonical);
44614461
Decl->TypeForDecl = newType;
44624462
Types.push_back(newType);
44634463
return QualType(newType, 0);

clang/lib/AST/Type.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3369,8 +3369,9 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID,
33693369
getExtProtoInfo(), Ctx, isCanonicalUnqualified());
33703370
}
33713371

3372-
TypedefType::TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType can)
3373-
: Type(tc, can, D->getUnderlyingType()->getDependence()),
3372+
TypedefType::TypedefType(TypeClass tc, const TypedefNameDecl *D,
3373+
QualType underlying, QualType can)
3374+
: Type(tc, can, underlying->getDependence()),
33743375
Decl(const_cast<TypedefNameDecl *>(D)) {
33753376
assert(!isa<TypedefType>(can) && "Invalid canonical type");
33763377
}

clang/test/PCH/cxx-templates.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,8 @@ namespace DependentTemplateName {
180180
getWithIdentifier<HasMember>();
181181
}
182182
}
183+
184+
namespace ClassTemplateCycle {
185+
extern T t;
186+
int k = M;
187+
}

clang/test/PCH/cxx-templates.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,3 +456,19 @@ namespace DependentTemplateName {
456456
template <class T>
457457
TakesClassTemplate<T::template Member> getWithIdentifier();
458458
}
459+
460+
namespace ClassTemplateCycle {
461+
// Create a cycle: the typedef T refers to A<0, 8>, whose template argument
462+
// list refers back to T.
463+
template<int, int> struct A;
464+
using T = A<0, sizeof(void*)>;
465+
template<int N> struct A<N, sizeof(T*)> {};
466+
T t;
467+
468+
// Create a cycle: the variable M refers to A<1, 1>, whose template argument
469+
// list list refers back to M.
470+
template<int, int> struct A;
471+
const decltype(sizeof(A<1, 1>*)) M = 1;
472+
template<int N> struct A<N, M> {};
473+
A<1, 1> u;
474+
}

0 commit comments

Comments
 (0)