Author: Aaron Ballman Date: 2023-04-14T07:19:33-04:00 New Revision: b0e61de7075942ef5ac8af9ca1ec918317f62152
URL: https://github.com/llvm/llvm-project/commit/b0e61de7075942ef5ac8af9ca1ec918317f62152 DIFF: https://github.com/llvm/llvm-project/commit/b0e61de7075942ef5ac8af9ca1ec918317f62152.diff LOG: Model list initialization more directly; fixes an assert with coverage mapping 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. Fixes https://github.com/llvm/llvm-project/issues/62105 Differential Revision: https://reviews.llvm.org/D148245 Added: clang/test/Coverage/unresolved-ctor-expr.cpp Modified: 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 Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b838858c09179..d854590363a54 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -300,6 +300,8 @@ Bug Fixes in This Version - 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 diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 032fd199b0301..724904b4d2041 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -3504,8 +3504,9 @@ class CXXUnresolvedConstructExpr final 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 @@ class CXXUnresolvedConstructExpr final 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 @@ class CXXUnresolvedConstructExpr final /// 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; } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 10392d294524a..44a5f77fa6c24 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -8147,7 +8147,7 @@ ExpectedStmt ASTNodeImporter::VisitCXXUnresolvedConstructExpr( return CXXUnresolvedConstructExpr::Create( Importer.getToContext(), ToType, ToTypeSourceInfo, ToLParenLoc, - llvm::ArrayRef(ToArgs), ToRParenLoc); + llvm::ArrayRef(ToArgs), ToRParenLoc, E->isListInitialization()); } ExpectedStmt diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 2a9e335950138..9e1c39ff2f947 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -1392,17 +1392,16 @@ ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C, 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(QualType T, } 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 @@ CXXUnresolvedConstructExpr::CreateEmpty(const ASTContext &Context, } SourceLocation CXXUnresolvedConstructExpr::getBeginLoc() const { - return TSI->getTypeLoc().getBeginLoc(); + return TypeAndInitForm.getPointer()->getTypeLoc().getBeginLoc(); } CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr( diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index ccd605ac4ace0..0617d29aed712 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1522,16 +1522,10 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, 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 diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 5b16765e2971d..032f685a872e8 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -2006,9 +2006,10 @@ ASTStmtReader::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) { 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) { diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 9f10c01390d19..021765b69edea 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1921,6 +1921,7 @@ ASTStmtWriter::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) { Record.AddTypeSourceInfo(E->getTypeSourceInfo()); Record.AddSourceLocation(E->getLParenLoc()); Record.AddSourceLocation(E->getRParenLoc()); + Record.push_back(E->isListInitialization()); Code = serialization::EXPR_CXX_UNRESOLVED_CONSTRUCT; } diff --git a/clang/test/Coverage/unresolved-ctor-expr.cpp b/clang/test/Coverage/unresolved-ctor-expr.cpp new file mode 100644 index 0000000000000..10286c79f569d --- /dev/null +++ b/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(); +} + _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits