aaron.ballman created this revision. aaron.ballman added reviewers: erichkeane, rsmith, zequanwu. Herald added a subscriber: martong. Herald added a reviewer: shafik. Herald added a project: All. aaron.ballman requested review of this revision. Herald added a project: clang.
Instead of using the validity of a brace's source location as a flag for list initialization, this now uses a `PointerIntPair` to model it so we do not increase the size of the AST node to track this information. This allows us to retain the valid source location information, which fixes the coverage assertion. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D148245 Files: clang/docs/ReleaseNotes.rst clang/include/clang/AST/ExprCXX.h clang/lib/AST/ASTImporter.cpp clang/lib/AST/ExprCXX.cpp clang/lib/Sema/SemaExprCXX.cpp clang/lib/Serialization/ASTReaderStmt.cpp clang/lib/Serialization/ASTWriterStmt.cpp clang/test/Coverage/unresolved-ctor-expr.cpp
Index: clang/test/Coverage/unresolved-ctor-expr.cpp =================================================================== --- /dev/null +++ clang/test/Coverage/unresolved-ctor-expr.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 -fcoverage-mapping %s +// expected-no-diagnostics + +// GH62105 demonstrated a crash with this example code when calculating +// coverage mapping because some source location information was being dropped. +// Demonstrate that we do not crash on this code. +namespace std { template <typename> class initializer_list {}; } + +template <typename> struct T { + T(std::initializer_list<int>, int = int()); + bool b; +}; + +template <typename> struct S1 { + static void foo() { + class C; + (void)(0 ? T<C>{} : T<C>{}); + } +}; + +void bar() { + S1<int>::foo(); +} + Index: clang/lib/Serialization/ASTWriterStmt.cpp =================================================================== --- clang/lib/Serialization/ASTWriterStmt.cpp +++ clang/lib/Serialization/ASTWriterStmt.cpp @@ -1921,6 +1921,7 @@ Record.AddTypeSourceInfo(E->getTypeSourceInfo()); Record.AddSourceLocation(E->getLParenLoc()); Record.AddSourceLocation(E->getRParenLoc()); + Record.push_back(E->isListInitialization()); Code = serialization::EXPR_CXX_UNRESOLVED_CONSTRUCT; } Index: clang/lib/Serialization/ASTReaderStmt.cpp =================================================================== --- clang/lib/Serialization/ASTReaderStmt.cpp +++ clang/lib/Serialization/ASTReaderStmt.cpp @@ -2006,9 +2006,10 @@ Record.skipInts(1); for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) E->setArg(I, Record.readSubExpr()); - E->TSI = readTypeSourceInfo(); + E->TypeAndInitForm.setPointer(readTypeSourceInfo()); E->setLParenLoc(readSourceLocation()); E->setRParenLoc(readSourceLocation()); + E->TypeAndInitForm.setInt(Record.readInt()); } void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) { Index: clang/lib/Sema/SemaExprCXX.cpp =================================================================== --- clang/lib/Sema/SemaExprCXX.cpp +++ clang/lib/Sema/SemaExprCXX.cpp @@ -1522,16 +1522,10 @@ Entity = InitializedEntity::InitializeTemporary(TInfo, Ty); } - if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) { - // FIXME: CXXUnresolvedConstructExpr does not model list-initialization - // directly. We work around this by dropping the locations of the braces. - SourceRange Locs = ListInitialization - ? SourceRange() - : SourceRange(LParenOrBraceLoc, RParenOrBraceLoc); - return CXXUnresolvedConstructExpr::Create(Context, Ty.getNonReferenceType(), - TInfo, Locs.getBegin(), Exprs, - Locs.getEnd()); - } + if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) + return CXXUnresolvedConstructExpr::Create( + Context, Ty.getNonReferenceType(), TInfo, LParenOrBraceLoc, Exprs, + RParenOrBraceLoc, ListInitialization); // C++ [expr.type.conv]p1: // If the expression list is a parenthesized single expression, the type Index: clang/lib/AST/ExprCXX.cpp =================================================================== --- clang/lib/AST/ExprCXX.cpp +++ clang/lib/AST/ExprCXX.cpp @@ -1392,17 +1392,16 @@ return new (buffer) ExprWithCleanups(empty, numObjects); } -CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(QualType T, - TypeSourceInfo *TSI, - SourceLocation LParenLoc, - ArrayRef<Expr *> Args, - SourceLocation RParenLoc) +CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr( + QualType T, TypeSourceInfo *TSI, SourceLocation LParenLoc, + ArrayRef<Expr *> Args, SourceLocation RParenLoc, bool IsListInit) : Expr(CXXUnresolvedConstructExprClass, T, (TSI->getType()->isLValueReferenceType() ? VK_LValue : TSI->getType()->isRValueReferenceType() ? VK_XValue : VK_PRValue), OK_Ordinary), - TSI(TSI), LParenLoc(LParenLoc), RParenLoc(RParenLoc) { + TypeAndInitForm(TSI, IsListInit), LParenLoc(LParenLoc), + RParenLoc(RParenLoc) { CXXUnresolvedConstructExprBits.NumArgs = Args.size(); auto **StoredArgs = getTrailingObjects<Expr *>(); for (unsigned I = 0; I != Args.size(); ++I) @@ -1411,11 +1410,12 @@ } CXXUnresolvedConstructExpr *CXXUnresolvedConstructExpr::Create( - const ASTContext &Context, QualType T, TypeSourceInfo *TSI, SourceLocation LParenLoc, - ArrayRef<Expr *> Args, SourceLocation RParenLoc) { + const ASTContext &Context, QualType T, TypeSourceInfo *TSI, + SourceLocation LParenLoc, ArrayRef<Expr *> Args, SourceLocation RParenLoc, + bool IsListInit) { void *Mem = Context.Allocate(totalSizeToAlloc<Expr *>(Args.size())); - return new (Mem) - CXXUnresolvedConstructExpr(T, TSI, LParenLoc, Args, RParenLoc); + return new (Mem) CXXUnresolvedConstructExpr(T, TSI, LParenLoc, Args, + RParenLoc, IsListInit); } CXXUnresolvedConstructExpr * @@ -1426,7 +1426,7 @@ } SourceLocation CXXUnresolvedConstructExpr::getBeginLoc() const { - return TSI->getTypeLoc().getBeginLoc(); + return TypeAndInitForm.getPointer()->getTypeLoc().getBeginLoc(); } CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr( Index: clang/lib/AST/ASTImporter.cpp =================================================================== --- clang/lib/AST/ASTImporter.cpp +++ clang/lib/AST/ASTImporter.cpp @@ -8147,7 +8147,7 @@ return CXXUnresolvedConstructExpr::Create( Importer.getToContext(), ToType, ToTypeSourceInfo, ToLParenLoc, - llvm::ArrayRef(ToArgs), ToRParenLoc); + llvm::ArrayRef(ToArgs), ToRParenLoc, E->isListInitialization()); } ExpectedStmt Index: clang/include/clang/AST/ExprCXX.h =================================================================== --- clang/include/clang/AST/ExprCXX.h +++ clang/include/clang/AST/ExprCXX.h @@ -3504,8 +3504,9 @@ friend class ASTStmtReader; friend TrailingObjects; - /// The type being constructed. - TypeSourceInfo *TSI; + /// The type being constructed, and whether the construct expression models + /// list initialization or not. + llvm::PointerIntPair<TypeSourceInfo *, 1> TypeAndInitForm; /// The location of the left parentheses ('('). SourceLocation LParenLoc; @@ -3515,30 +3516,31 @@ CXXUnresolvedConstructExpr(QualType T, TypeSourceInfo *TSI, SourceLocation LParenLoc, ArrayRef<Expr *> Args, - SourceLocation RParenLoc); + SourceLocation RParenLoc, bool IsListInit); CXXUnresolvedConstructExpr(EmptyShell Empty, unsigned NumArgs) - : Expr(CXXUnresolvedConstructExprClass, Empty), TSI(nullptr) { + : Expr(CXXUnresolvedConstructExprClass, Empty) { CXXUnresolvedConstructExprBits.NumArgs = NumArgs; } public: - static CXXUnresolvedConstructExpr *Create(const ASTContext &Context, - QualType T, TypeSourceInfo *TSI, - SourceLocation LParenLoc, - ArrayRef<Expr *> Args, - SourceLocation RParenLoc); + static CXXUnresolvedConstructExpr * + Create(const ASTContext &Context, QualType T, TypeSourceInfo *TSI, + SourceLocation LParenLoc, ArrayRef<Expr *> Args, + SourceLocation RParenLoc, bool IsListInit); static CXXUnresolvedConstructExpr *CreateEmpty(const ASTContext &Context, unsigned NumArgs); /// Retrieve the type that is being constructed, as specified /// in the source code. - QualType getTypeAsWritten() const { return TSI->getType(); } + QualType getTypeAsWritten() const { return getTypeSourceInfo()->getType(); } /// Retrieve the type source information for the type being /// constructed. - TypeSourceInfo *getTypeSourceInfo() const { return TSI; } + TypeSourceInfo *getTypeSourceInfo() const { + return TypeAndInitForm.getPointer(); + } /// Retrieve the location of the left parentheses ('(') that /// precedes the argument list. @@ -3553,7 +3555,7 @@ /// Determine whether this expression models list-initialization. /// If so, there will be exactly one subexpression, which will be /// an InitListExpr. - bool isListInitialization() const { return LParenLoc.isInvalid(); } + bool isListInitialization() const { return TypeAndInitForm.getInt(); } /// Retrieve the number of arguments. unsigned getNumArgs() const { return CXXUnresolvedConstructExprBits.NumArgs; } Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -300,6 +300,8 @@ - Work around with a clang coverage crash which happens when visiting expressions/statements with invalid source locations in non-assert builds. Assert builds may still see assertions triggered from this. +- Fix a failed assertion due to an invalid source location when trying to form + a coverage report for an unresolved constructor expression. (`#62105 <https://github.com/llvm/llvm-project/issues/62105>`_) Bug Fixes to Compiler Builtins
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits