https://github.com/bolshakov-a updated https://github.com/llvm/llvm-project/pull/195175
>From ed7f9674bd014024a53061419e189e7a8e4ebca6 Mon Sep 17 00:00:00 2001 From: Bolshakov <[email protected]> Date: Thu, 30 Apr 2026 10:31:34 +0300 Subject: [PATCH 1/3] [clang] Make `InitListExpr::isExplicit()` work The main goal of this change is to be able to use `isExplicit()` check in the IWYU tool. Consider the following: struct Inner {}; struct Outer { Inner inner; }; const Outer& refOuter = {}; Here, Clang generates `InitListExpr` child node for the implicit `Inner` initialization under the `InitListExpr` node corresponding to the initializer of `refOuter`. IWYU should require the header containing `Outer` definition for the initializer, but not the header for `Inner` because it should be already provided by `Outer`. 'IsExplicit' flag is copied from a template instantiation pattern into its instantiations although they are implicit because it makes sense for IWYU at least. (After all, instantiated declarations refer to the pattern explicitly written in the source.) This is an NFC from the point of view of users of the Clang standalone executable (except the change in AST dumping), but a functional change for those who use Clang as a library. --- .../utils/DesignatedInitializers.cpp | 26 +- clang/docs/LibASTMatchersReference.html | 2 +- clang/include/clang/AST/Expr.h | 9 +- clang/include/clang/AST/Stmt.h | 4 + clang/include/clang/ASTMatchers/ASTMatchers.h | 4 +- clang/include/clang/Sema/Sema.h | 2 +- clang/lib/AST/ASTImporter.cpp | 4 +- clang/lib/AST/Expr.cpp | 7 +- clang/lib/AST/TextNodeDumper.cpp | 1 + .../Frontend/Rewrite/RewriteModernObjC.cpp | 8 +- clang/lib/Frontend/Rewrite/RewriteObjC.cpp | 8 +- clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 4 +- clang/lib/Sema/SemaExpr.cpp | 21 +- clang/lib/Sema/SemaHLSL.cpp | 10 +- clang/lib/Sema/SemaInit.cpp | 40 +-- clang/lib/Sema/SemaOpenACC.cpp | 15 +- clang/lib/Sema/SemaOverload.cpp | 2 +- clang/lib/Sema/SemaTemplate.cpp | 3 +- clang/lib/Sema/TreeTransform.h | 15 +- clang/lib/Serialization/ASTReaderStmt.cpp | 1 + clang/lib/Serialization/ASTWriterStmt.cpp | 1 + clang/test/AST/HLSL/matrix-constructors.hlsl | 39 ++- clang/test/AST/ast-dump-decl.cpp | 12 +- clang/test/AST/ast-dump-stmt.cpp | 6 +- clang/test/CXX/drs/cwg2149.cpp | 12 +- clang/test/SemaCXX/compound-literal.cpp | 6 +- clang/test/SemaHLSL/Language/InitListAST.hlsl | 22 +- clang/unittests/AST/ASTExprTest.cpp | 247 +++++++++++++++++- clang/unittests/AST/ASTImporterTest.cpp | 28 +- 29 files changed, 414 insertions(+), 145 deletions(-) diff --git a/clang-tools-extra/clang-tidy/utils/DesignatedInitializers.cpp b/clang-tools-extra/clang-tidy/utils/DesignatedInitializers.cpp index 908a1b5ec4e09..7efcd614cd2ac 100644 --- a/clang-tools-extra/clang-tidy/utils/DesignatedInitializers.cpp +++ b/clang-tools-extra/clang-tidy/utils/DesignatedInitializers.cpp @@ -14,7 +14,6 @@ #include "DesignatedInitializers.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Type.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/ScopeExit.h" namespace clang::tidy::utils { @@ -129,9 +128,9 @@ class AggregateDesignatorNames { // '.a:' is produced directly without recursing into the written sublist. // (The written sublist will have a separate collectDesignators() call later). // Recursion with Prefix='.b' and Sem = {3, ImplicitValue} produces '.b.x:'. -static void collectDesignators( - const InitListExpr *Sem, llvm::DenseMap<SourceLocation, std::string> &Out, - const llvm::DenseSet<SourceLocation> &NestedBraces, std::string &Prefix) { +static void collectDesignators(const InitListExpr *Sem, + llvm::DenseMap<SourceLocation, std::string> &Out, + std::string &Prefix) { if (!Sem || Sem->isTransparent()) return; assert(Sem->isSemanticForm()); @@ -152,8 +151,7 @@ static void collectDesignators( continue; const auto *BraceElidedSubobject = dyn_cast<InitListExpr>(Init); - if (BraceElidedSubobject && - NestedBraces.contains(BraceElidedSubobject->getLBraceLoc())) + if (BraceElidedSubobject && BraceElidedSubobject->isExplicit()) BraceElidedSubobject = nullptr; // there were braces! if (!Fields.append(Prefix, BraceElidedSubobject != nullptr)) @@ -162,9 +160,7 @@ static void collectDesignators( // If the braces were elided, this aggregate subobject is initialized // inline in the same syntactic list. // Descend into the semantic list describing the subobject. - // (NestedBraces are still correct, they're from the same syntactic - // list). - collectDesignators(BraceElidedSubobject, Out, NestedBraces, Prefix); + collectDesignators(BraceElidedSubobject, Out, Prefix); continue; } Out.try_emplace(Init->getBeginLoc(), Prefix); @@ -173,22 +169,12 @@ static void collectDesignators( llvm::DenseMap<SourceLocation, std::string> getUnwrittenDesignators(const InitListExpr *Syn) { - assert(Syn->isSyntacticForm()); - - // collectDesignators needs to know which InitListExprs in the semantic tree - // were actually written, but InitListExpr::isExplicit() lies. - // Instead, record where braces of sub-init-lists occur in the syntactic form. - llvm::DenseSet<SourceLocation> NestedBraces; - for (const Expr *Init : Syn->inits()) - if (auto *Nested = dyn_cast<InitListExpr>(Init)) - NestedBraces.insert(Nested->getLBraceLoc()); - // Traverse the semantic form to find the designators. // We use their SourceLocation to correlate with the syntactic form later. llvm::DenseMap<SourceLocation, std::string> Designators; std::string EmptyPrefix; collectDesignators(Syn->isSemanticForm() ? Syn : Syn->getSemanticForm(), - Designators, NestedBraces, EmptyPrefix); + Designators, EmptyPrefix); return Designators; } diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index 9f9d4223bb50a..b13eec72f9e3b 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -3322,7 +3322,7 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2> <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('isExplicit0')"><a name="isExplicit0Anchor">isExplicit</a></td><td></td></tr> <tr><td colspan="4" class="doc" id="isExplicit0"><pre>Matches constructor, conversion function, and deduction guide declarations that have an explicit specifier if this explicit specifier is resolved to -true. +true. Also matches explicitly written initializer list expressions. Given template<bool b> diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index a0ab599fa82d2..7ef7b3d030d43 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -5323,7 +5323,8 @@ class InitListExpr : public Expr { public: InitListExpr(const ASTContext &C, SourceLocation lbraceloc, - ArrayRef<Expr*> initExprs, SourceLocation rbraceloc); + ArrayRef<Expr *> initExprs, SourceLocation rbraceloc, + bool isExplicit); /// Build an empty initializer list. explicit InitListExpr(EmptyShell Empty) @@ -5441,11 +5442,7 @@ class InitListExpr : public Expr { // Explicit InitListExpr's originate from source code (and have valid source // locations). Implicit InitListExpr's are created by the semantic analyzer. - // FIXME: This is wrong; InitListExprs created by semantic analysis have - // valid source locations too! - bool isExplicit() const { - return LBraceLoc.isValid() && RBraceLoc.isValid(); - } + bool isExplicit() const { return InitListExprBits.IsExplicit; } /// Is this an initializer for an array of characters, initialized by a string /// literal or an @encode? diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index d940aa6562c4c..f07ba9205661b 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -670,6 +670,7 @@ class alignas(void *) Stmt { }; class InitListExprBitfields { + friend class ASTStmtReader; friend class InitListExpr; LLVM_PREFERRED_TYPE(ExprBitfields) @@ -679,6 +680,9 @@ class alignas(void *) Stmt { /// designator in it. This is a temporary marker used by CodeGen. LLVM_PREFERRED_TYPE(bool) unsigned HadArrayRangeDesignator : 1; + // Whether this list is explicitly written in the source (with braces). + LLVM_PREFERRED_TYPE(bool) + unsigned IsExplicit : 1; }; class ParenListExprBitfields { diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index e7e70e59dfedd..ffceb9269fc6e 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -8122,7 +8122,7 @@ AST_MATCHER(CXXConstructorDecl, isDelegatingConstructor) { /// Matches constructor, conversion function, and deduction guide declarations /// that have an explicit specifier if this explicit specifier is resolved to -/// true. +/// true. Also matches explicitly written initializer list expressions. /// /// Given /// \code @@ -8144,7 +8144,7 @@ AST_MATCHER(CXXConstructorDecl, isDelegatingConstructor) { /// cxxDeductionGuideDecl(isExplicit()) will match #6, but not #5. AST_POLYMORPHIC_MATCHER(isExplicit, AST_POLYMORPHIC_SUPPORTED_TYPES( CXXConstructorDecl, CXXConversionDecl, - CXXDeductionGuideDecl)) { + CXXDeductionGuideDecl, InitListExpr)) { return Node.isExplicit(); } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f9bf3e4de0a5e..b24ddd0e1ca6b 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7595,7 +7595,7 @@ class Sema final : public SemaBase { SourceLocation RBraceLoc); ExprResult BuildInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, - SourceLocation RBraceLoc); + SourceLocation RBraceLoc, bool IsExplicit); /// Binary Operators. 'Tok' is the token for the operator. ExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind, diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 4c8cc31421200..3001f18c98605 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -9028,8 +9028,8 @@ ExpectedStmt ASTNodeImporter::VisitInitListExpr(InitListExpr *E) { return std::move(Err); ASTContext &ToCtx = Importer.getToContext(); - InitListExpr *To = new (ToCtx) InitListExpr( - ToCtx, ToLBraceLoc, ToExprs, ToRBraceLoc); + InitListExpr *To = new (ToCtx) + InitListExpr(ToCtx, ToLBraceLoc, ToExprs, ToRBraceLoc, E->isExplicit()); To->setType(ToType); if (E->hasArrayFiller()) { diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 64d61dbc3d128..d5048f7aecad0 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -2404,12 +2404,14 @@ EmbedExpr::EmbedExpr(const ASTContext &Ctx, SourceLocation Loc, } InitListExpr::InitListExpr(const ASTContext &C, SourceLocation lbraceloc, - ArrayRef<Expr *> initExprs, SourceLocation rbraceloc) + ArrayRef<Expr *> initExprs, SourceLocation rbraceloc, + bool isExplicit) : Expr(InitListExprClass, QualType(), VK_PRValue, OK_Ordinary), InitExprs(C, initExprs.size()), LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(nullptr, true) { sawArrayRangeDesignator(false); InitExprs.insert(C, InitExprs.end(), initExprs.begin(), initExprs.end()); + InitListExprBits.IsExplicit = isExplicit; setDependence(computeDependence(this)); } @@ -4933,7 +4935,8 @@ DesignatedInitUpdateExpr::DesignatedInitUpdateExpr(const ASTContext &C, OK_Ordinary) { BaseAndUpdaterExprs[0] = baseExpr; - InitListExpr *ILE = new (C) InitListExpr(C, lBraceLoc, {}, rBraceLoc); + InitListExpr *ILE = + new (C) InitListExpr(C, lBraceLoc, {}, rBraceLoc, /*isExplicit=*/false); ILE->setType(baseExpr->getType()); BaseAndUpdaterExprs[1] = ILE; diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 53982025dfd4d..ed2c1d72a9fa2 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1648,6 +1648,7 @@ void TextNodeDumper::VisitInitListExpr(const InitListExpr *ILE) { OS << " field "; dumpBareDeclRef(Field); } + OS << ' ' << (ILE->isExplicit() ? "explicit" : "implicit"); } void TextNodeDumper::VisitGenericSelectionExpr(const GenericSelectionExpr *E) { diff --git a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp index dee29fe004f42..12442040b13bb 100644 --- a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -3294,8 +3294,8 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, } else { // (struct __rw_objc_super) { <exprs from above> } InitListExpr *ILE = - new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, - SourceLocation()); + new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, + SourceLocation(), /*isExplicit=*/true); TypeSourceInfo *superTInfo = Context->getTrivialTypeSourceInfo(superType); SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, @@ -3386,8 +3386,8 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, } else { // (struct __rw_objc_super) { <exprs from above> } InitListExpr *ILE = - new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, - SourceLocation()); + new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, + SourceLocation(), /*isExplicit=*/true); TypeSourceInfo *superTInfo = Context->getTrivialTypeSourceInfo(superType); SuperRep = new (Context) CompoundLiteralExpr( diff --git a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp index b9c025de87739..6b8753e29b8fe 100644 --- a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp +++ b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp @@ -2722,8 +2722,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, } else { // (struct objc_super) { <exprs from above> } InitListExpr *ILE = - new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, - SourceLocation()); + new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, + SourceLocation(), /*isExplicit=*/true); TypeSourceInfo *superTInfo = Context->getTrivialTypeSourceInfo(superType); SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, @@ -2814,8 +2814,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, } else { // (struct objc_super) { <exprs from above> } InitListExpr *ILE = - new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, - SourceLocation()); + new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, + SourceLocation(), /*isExplicit=*/true); TypeSourceInfo *superTInfo = Context->getTrivialTypeSourceInfo(superType); SuperRep = new (Context) CompoundLiteralExpr( diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index ba8e63f01527a..af9c7de2d855d 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -649,8 +649,8 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::concat(V Vec, S Scalar, } Elts.push_back(ScalarExpr); - auto *InitList = - new (AST) InitListExpr(AST, SourceLocation(), Elts, SourceLocation()); + auto *InitList = new (AST) InitListExpr( + AST, SourceLocation(), Elts, SourceLocation(), /*isExplicit=*/false); InitList->setType(ResultTy); ExprResult Cast = DeclBuilder.SemaRef.BuildCStyleCastExpr( diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c494669420282..0fe296e3f8a91 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -7594,12 +7594,12 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, } } - return BuildInitList(LBraceLoc, InitArgList, RBraceLoc); + return BuildInitList(LBraceLoc, InitArgList, RBraceLoc, /*IsExplicit=*/true); } -ExprResult -Sema::BuildInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, - SourceLocation RBraceLoc) { +ExprResult Sema::BuildInitList(SourceLocation LBraceLoc, + MultiExprArg InitArgList, + SourceLocation RBraceLoc, bool IsExplicit) { // Semantic analysis for initializers is done by ActOnDeclarator() and // CheckInitializer() - it requires knowledge of the object being initialized. @@ -7617,8 +7617,8 @@ Sema::BuildInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, } } - InitListExpr *E = - new (Context) InitListExpr(Context, LBraceLoc, InitArgList, RBraceLoc); + InitListExpr *E = new (Context) + InitListExpr(Context, LBraceLoc, InitArgList, RBraceLoc, IsExplicit); E->setType(Context.VoidTy); // FIXME: just a place holder for now. return E; } @@ -8287,8 +8287,9 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, } // FIXME: This means that pretty-printing the final AST will produce curly // braces instead of the original commas. - InitListExpr *initE = new (Context) InitListExpr(Context, LiteralLParenLoc, - initExprs, LiteralRParenLoc); + InitListExpr *initE = + new (Context) InitListExpr(Context, LiteralLParenLoc, initExprs, + LiteralRParenLoc, /*isExplicit=*/false); initE->setType(Ty); return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, initE); } @@ -10045,8 +10046,8 @@ static void ConstructTransparentUnion(Sema &S, ASTContext &C, // Build an initializer list that designates the appropriate member // of the transparent union. Expr *E = EResult.get(); - InitListExpr *Initializer = new (C) InitListExpr(C, SourceLocation(), - E, SourceLocation()); + InitListExpr *Initializer = new (C) InitListExpr( + C, SourceLocation(), E, SourceLocation(), /*isExplicit=*/false); Initializer->setType(UnionType); Initializer->setInitializedFieldInUnion(Field); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index aba1c5072a5fc..1541c0954f764 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -5933,8 +5933,9 @@ class InitListTransformer { Inits.push_back(generateInitListsImpl(FD->getType())); } } - auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(), - Inits, Inits.back()->getEndLoc()); + auto *NewInit = + new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(), Inits, + Inits.back()->getEndLoc(), /*isExplicit=*/false); NewInit->setType(Ty); return NewInit; } @@ -5970,8 +5971,9 @@ class InitListTransformer { while (ArgIt != ArgExprs.end()) Inits.push_back(generateInitListsImpl(InitTy)); - auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(), - Inits, Inits.back()->getEndLoc()); + auto *NewInit = + new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(), Inits, + Inits.back()->getEndLoc(), /*isExplicit=*/false); llvm::APInt ArySize(64, Inits.size()); NewInit->setType(Ctx.getConstantArrayType(InitTy, ArySize, nullptr, ArraySizeModifier::Normal, 0)); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index e54a25405c816..2521684212b91 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -449,7 +449,7 @@ class InitListChecker { Expr *expr); InitListExpr *createInitListExpr(QualType CurrentObjectType, SourceRange InitRange, - unsigned ExpectedNumInits); + unsigned ExpectedNumInits, bool IsExplicit); int numArrayElements(QualType DeclType); int numStructUnionElements(QualType DeclType); @@ -619,7 +619,8 @@ ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc, true); MultiExprArg SubInit; Expr *InitExpr; - InitListExpr DummyInitList(SemaRef.Context, Loc, {}, Loc); + InitListExpr DummyInitList(SemaRef.Context, Loc, {}, Loc, + /*isExplicit=*/false); // C++ [dcl.init.aggr]p7: // If there are fewer initializer-clauses in the list than there are @@ -640,7 +641,8 @@ ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc, // the initializer list where possible. InitExpr = VerifyOnly ? &DummyInitList : new (SemaRef.Context) - InitListExpr(SemaRef.Context, Loc, {}, Loc); + InitListExpr(SemaRef.Context, Loc, {}, Loc, + /*isExplicit=*/false); InitExpr->setType(SemaRef.Context.VoidTy); SubInit = InitExpr; Kind = InitializationKind::CreateCopy(Loc, Loc); @@ -1098,8 +1100,8 @@ InitListChecker::InitListChecker( InOverloadResolution(InOverloadResolution), AggrDeductionCandidateParamTypes(AggrDeductionCandidateParamTypes) { if (!VerifyOnly || hasAnyDesignatedInits(IL)) { - FullyStructuredList = - createInitListExpr(T, IL->getSourceRange(), IL->getNumInits()); + FullyStructuredList = createInitListExpr( + T, IL->getSourceRange(), IL->getNumInits(), IL->isExplicit()); // FIXME: Check that IL isn't already the semantic form of some other // InitListExpr. If it is, we'd create a broken AST. @@ -3550,8 +3552,8 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, ExpectedNumInits = IList->getNumInits() - Index; } - InitListExpr *Result = - createInitListExpr(CurrentObjectType, InitRange, ExpectedNumInits); + InitListExpr *Result = createInitListExpr( + CurrentObjectType, InitRange, ExpectedNumInits, /*IsExplicit=*/false); // Link this new initializer list into the structured initializer // lists. @@ -3559,12 +3561,13 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, return Result; } -InitListExpr * -InitListChecker::createInitListExpr(QualType CurrentObjectType, - SourceRange InitRange, - unsigned ExpectedNumInits) { - InitListExpr *Result = new (SemaRef.Context) InitListExpr( - SemaRef.Context, InitRange.getBegin(), {}, InitRange.getEnd()); +InitListExpr *InitListChecker::createInitListExpr(QualType CurrentObjectType, + SourceRange InitRange, + unsigned ExpectedNumInits, + bool IsExplicit) { + InitListExpr *Result = new (SemaRef.Context) + InitListExpr(SemaRef.Context, InitRange.getBegin(), {}, + InitRange.getEnd(), /*isExplicit=*/IsExplicit); QualType ResultType = CurrentObjectType; if (!ResultType->isArrayType()) @@ -6993,7 +6996,7 @@ void InitializationSequence::InitializeFrom(Sema &S, if (ShouldTryListInitialization()) { InitListExpr *ILE = new (Context) InitListExpr(S.getASTContext(), Args.front()->getBeginLoc(), Args, - Args.back()->getEndLoc()); + Args.back()->getEndLoc(), /*isExplicit=*/false); ILE->setType(DestType); Args[0] = ILE; TryListInitialization(S, Entity, Kind, ILE, *this, @@ -8444,8 +8447,10 @@ ExprResult InitializationSequence::Perform(Sema &S, case SK_RewrapInitList: { Expr *E = CurInit.get(); InitListExpr *Syntactic = Step->WrappingSyntacticList; - InitListExpr *ILE = new (S.Context) InitListExpr(S.Context, - Syntactic->getLBraceLoc(), E, Syntactic->getRBraceLoc()); + assert(Syntactic->isExplicit()); + InitListExpr *ILE = new (S.Context) + InitListExpr(S.Context, Syntactic->getLBraceLoc(), E, + Syntactic->getRBraceLoc(), /*isExplicit=*/true); ILE->setSyntacticForm(Syntactic); ILE->setType(E->getType()); ILE->setValueKind(E->getValueKind()); @@ -10384,7 +10389,8 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( // the parentheses source locations, use the begin/end of Inits as the // best heuristic. InitListExpr TempListInit(getASTContext(), Inits.front()->getBeginLoc(), - Inits, Inits.back()->getEndLoc()); + Inits, Inits.back()->getEndLoc(), + /*isExplicit=*/false); SynthesizeAggrGuide(&TempListInit); } } diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index a228d224e2308..79edb8093c368 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -2662,8 +2662,9 @@ Expr *GenerateReductionInitRecipeExpr(ASTContext &Context, return nullptr; if (IK == InitKind::Zero) { - Expr *InitExpr = new (Context) - InitListExpr(Context, ExprRange.getBegin(), {}, ExprRange.getEnd()); + Expr *InitExpr = + new (Context) InitListExpr(Context, ExprRange.getBegin(), {}, + ExprRange.getEnd(), /*isExplicit=*/false); InitExpr->setType(Context.VoidTy); return InitExpr; } @@ -2739,8 +2740,9 @@ Expr *GenerateReductionInitRecipeExpr(ASTContext &Context, } } - Expr *InitExpr = new (Context) - InitListExpr(Context, ExprRange.getBegin(), Exprs, ExprRange.getEnd()); + Expr *InitExpr = + new (Context) InitListExpr(Context, ExprRange.getBegin(), Exprs, + ExprRange.getEnd(), /*isExplicit=*/false); InitExpr->setType(Ty); return InitExpr; } @@ -2889,8 +2891,9 @@ SemaOpenACC::CreateFirstPrivateInitRecipe(const Expr *VarExpr) { Args.push_back(ElemRes.get()); } - Expr *InitExpr = new (getASTContext()) InitListExpr( - getASTContext(), VarExpr->getBeginLoc(), Args, VarExpr->getEndLoc()); + Expr *InitExpr = new (getASTContext()) + InitListExpr(getASTContext(), VarExpr->getBeginLoc(), Args, + VarExpr->getEndLoc(), /*isExplicit=*/false); InitExpr->setType(VarTy); ExprResult Init = FinishValueInit(SemaRef.SemaRef, Entity, diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 96c4ce489fe04..291f5313f13f6 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5835,7 +5835,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, if (CT->getSize().ugt(e)) { // Need an init from empty {}, is there one? InitListExpr EmptyList(S.Context, From->getEndLoc(), {}, - From->getEndLoc()); + From->getEndLoc(), /*isExplicit=*/false); EmptyList.setType(S.Context.VoidTy); DfltElt = TryListConversion( S, &EmptyList, InitTy, SuppressUserConversions, diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 7b7d43ef3234c..d56c675ba329e 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -8100,7 +8100,8 @@ static Expr *BuildExpressionFromIntegralTemplateArgumentValue( static Expr *BuildExpressionFromNonTypeTemplateArgumentValue( Sema &S, QualType T, const APValue &Val, SourceLocation Loc) { auto MakeInitList = [&](ArrayRef<Expr *> Elts) -> Expr * { - auto *ILE = new (S.Context) InitListExpr(S.Context, Loc, Elts, Loc); + auto *ILE = new (S.Context) + InitListExpr(S.Context, Loc, Elts, Loc, /*isExplicit=*/false); ILE->setType(T); return ILE; }; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 40187f71231bd..c3bf71dbf10df 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3129,10 +3129,9 @@ class TreeTransform { /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildInitList(SourceLocation LBraceLoc, - MultiExprArg Inits, - SourceLocation RBraceLoc) { - return SemaRef.BuildInitList(LBraceLoc, Inits, RBraceLoc); + ExprResult RebuildInitList(SourceLocation LBraceLoc, MultiExprArg Inits, + SourceLocation RBraceLoc, bool IsExplicit) { + return SemaRef.BuildInitList(LBraceLoc, Inits, RBraceLoc, IsExplicit); } /// Build a new designated initializer expression. @@ -4532,7 +4531,8 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init, // If this was list initialization, revert to syntactic list form. if (Construct->isListInitialization()) return getDerived().RebuildInitList(Construct->getBeginLoc(), NewArgs, - Construct->getEndLoc()); + Construct->getEndLoc(), + /*IsExplicit=*/true); // Build a ParenListExpr to represent anything else. SourceRange Parens = Construct->getParenOrBraceRange(); @@ -14126,7 +14126,7 @@ TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) { } return getDerived().RebuildInitList(E->getLBraceLoc(), Inits, - E->getRBraceLoc()); + E->getRBraceLoc(), E->isExplicit()); } template<typename Derived> @@ -15738,7 +15738,8 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( return ExprError(); if (E->isListInitialization() && !E->isStdInitListInitialization()) { - ExprResult Res = RebuildInitList(E->getBeginLoc(), Args, E->getEndLoc()); + ExprResult Res = RebuildInitList(E->getBeginLoc(), Args, E->getEndLoc(), + /*IsExplicit=*/true); if (Res.isInvalid()) return ExprError(); Args = {Res.get()}; diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 4ada1dc58042d..39a37c6dacb2a 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1281,6 +1281,7 @@ void ASTStmtReader::VisitInitListExpr(InitListExpr *E) { for (unsigned I = 0; I != NumInits; ++I) E->updateInit(Record.getContext(), I, Record.readSubExpr()); } + E->InitListExprBits.IsExplicit = Record.readBool(); } void ASTStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) { diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 47cbef06c3cc4..e1613b777b95a 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1250,6 +1250,7 @@ void ASTStmtWriter::VisitInitListExpr(InitListExpr *E) { for (unsigned I = 0, N = E->getNumInits(); I != N; ++I) Record.AddStmt(E->getInit(I)); } + Record.writeBool(E->isExplicit()); Code = serialization::EXPR_INIT_LIST; } diff --git a/clang/test/AST/HLSL/matrix-constructors.hlsl b/clang/test/AST/HLSL/matrix-constructors.hlsl index ae61ab49f8573..fc46c4339766d 100644 --- a/clang/test/AST/HLSL/matrix-constructors.hlsl +++ b/clang/test/AST/HLSL/matrix-constructors.hlsl @@ -12,7 +12,7 @@ typedef float float4 __attribute__((ext_vector_type(4))); void ok() { // CHECK: VarDecl 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> col:{{[0-9]+}} A 'float2x3':'matrix<float, 2, 3>' cinit // CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x3':'matrix<float, 2, 3>' functional cast to float2x3 <NoOp> -// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x3':'matrix<float, 2, 3>' +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x3':'matrix<float, 2, 3>' implicit // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' <IntegralToFloating> // CHECK-NEXT: IntegerLiteral 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'int' 1 // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' <IntegralToFloating> @@ -29,14 +29,14 @@ void ok() { // CHECK: VarDecl 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> col:{{[0-9]+}} B 'float2x1':'matrix<float, 2, 1>' cinit // CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x1':'matrix<float, 2, 1>' functional cast to float2x1 <NoOp> -// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x1':'matrix<float, 2, 1>' +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x1':'matrix<float, 2, 1>' implicit // CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' 1.000000e+00 // CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' 2.000000e+00 float2x1 B = float2x1(1.0,2.0); // CHECK: VarDecl 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> col:{{[0-9]+}} C 'float2x1':'matrix<float, 2, 1>' cinit // CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x1':'matrix<float, 2, 1>' functional cast to float2x1 <NoOp> -// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x1':'matrix<float, 2, 1>' +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x1':'matrix<float, 2, 1>' implicit // CHECK-NEXT: UnaryOperator 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float' prefix '-' // CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' 1.000000e+00 // CHECK-NEXT: UnaryOperator 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float' prefix '-' @@ -46,12 +46,12 @@ void ok() { // CHECK: VarDecl 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> col:{{[0-9]+}} D 'float2x3':'matrix<float, 2, 3>' cinit // CHECK-NEXT: ExprWithCleanups 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x3':'matrix<float, 2, 3>' // CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x3':'matrix<float, 2, 3>' functional cast to float2x3 <NoOp> -// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x3':'matrix<float, 2, 3>' +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x3':'matrix<float, 2, 3>' implicit // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float' <LValueToRValue> // CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float' xvalue vectorcomponent // CHECK-NEXT: MaterializeTemporaryExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' xvalue // CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' functional cast to float2 <NoOp> -// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' implicit // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' <IntegralToFloating> // CHECK-NEXT: IntegerLiteral 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'int' 1 // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' <IntegralToFloating> @@ -61,7 +61,7 @@ void ok() { // CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float' xvalue vectorcomponent // CHECK-NEXT: MaterializeTemporaryExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' xvalue // CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' functional cast to float2 <NoOp> -// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' implicit // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' <IntegralToFloating> // CHECK-NEXT: IntegerLiteral 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'int' 1 // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' <IntegralToFloating> @@ -80,12 +80,12 @@ void ok() { // CHECK: VarDecl 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> col:{{[0-9]+}} E 'float2x3':'matrix<float, 2, 3>' cinit // CHECK-NEXT: ExprWithCleanups 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x3':'matrix<float, 2, 3>' // CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x3':'matrix<float, 2, 3>' functional cast to float2x3 <NoOp> -// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x3':'matrix<float, 2, 3>' +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x3':'matrix<float, 2, 3>' implicit // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float' <LValueToRValue> // CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float' xvalue vectorcomponent // CHECK-NEXT: MaterializeTemporaryExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' xvalue // CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' functional cast to float2 <NoOp> -// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' implicit // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' <IntegralToFloating> // CHECK-NEXT: IntegerLiteral 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'int' 1 // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' <IntegralToFloating> @@ -95,7 +95,7 @@ void ok() { // CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float' xvalue vectorcomponent // CHECK-NEXT: MaterializeTemporaryExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' xvalue // CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' functional cast to float2 <NoOp> -// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' implicit // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' <IntegralToFloating> // CHECK-NEXT: IntegerLiteral 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'int' 1 // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' <IntegralToFloating> @@ -105,7 +105,7 @@ void ok() { // CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float' xvalue vectorcomponent // CHECK-NEXT: MaterializeTemporaryExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' xvalue // CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' functional cast to float2 <NoOp> -// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' implicit // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' <IntegralToFloating> // CHECK-NEXT: IntegerLiteral 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'int' 3 // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' <IntegralToFloating> @@ -115,7 +115,7 @@ void ok() { // CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float' xvalue vectorcomponent // CHECK-NEXT: MaterializeTemporaryExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' xvalue // CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' functional cast to float2 <NoOp> -// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>' implicit // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' <IntegralToFloating> // CHECK-NEXT: IntegerLiteral 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'int' 3 // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' <IntegralToFloating> @@ -392,3 +392,20 @@ float2x2 GettingStrange3 = float2x2(s4); } +// CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <line:{{[0-9]+:[0-9]+}}, line:{{[0-9]+:[0-9]+}}> line:{{[0-9]+:[0-9]+}} used TplFn 'void ()' implicit_instantiation +// CHECK-NEXT: TemplateArgument type 'int' +// CHECK-NEXT: BuiltinType 0x{{[0-9a-fA-F]+}} 'int' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: DeclStmt +// CHECK-NEXT: VarDecl 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> col:{{[0-9]+}} X 'float2x1':'matrix<float, 2, 1>' cinit +// CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x1':'matrix<float, 2, 1>' functional cast to float2x1 <NoOp> +// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2x1':'matrix<float, 2, 1>' implicit +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' 1.000000e+00 +// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:{{[0-9]+}}> 'float' 2.000000e+00 +template <typename T> +void TplFn() { + float2x1 X = float2x1(1.0,2.0); +} +void Fn() { + TplFn<int>(); +} diff --git a/clang/test/AST/ast-dump-decl.cpp b/clang/test/AST/ast-dump-decl.cpp index ecbfacaf128e2..5e3896ebd53c9 100644 --- a/clang/test/AST/ast-dump-decl.cpp +++ b/clang/test/AST/ast-dump-decl.cpp @@ -724,7 +724,7 @@ namespace testCanonicalTemplate { // CHECK-NEXT: | |-NestedNameSpecifier TypeSpec 'S'{{$}} // CHECK-NEXT: | |-TemplateArgument type 'int'{{$}} // CHECK-NEXT: | | `-BuiltinType 0x{{.+}} 'int'{{$}} - // CHECK-NEXT: | `-InitListExpr 0x{{.+}} <col:32, col:34> 'int'{{$}} + // CHECK-NEXT: | `-InitListExpr 0x{{.+}} <col:32, col:34> 'int' explicit{{$}} // CHECK-NEXT: `-VarTemplateSpecializationDecl 0x{{.+}} <line:[[@LINE-19]]:7, col:43> col:43 referenced TestVarTemplate 'const int' implicit_instantiation static instantiated_from 0x{{.+}}{{$}} // CHECK-NEXT: `-TemplateArgument type 'int'{{$}} @@ -736,7 +736,7 @@ namespace testCanonicalTemplate { // CHECK-NEXT: |-TemplateTypeParmDecl 0x{{.+}} <line:[[@LINE-25]]:12, col:21> col:21 referenced typename depth 0 index 0 T{{$}} // CHECK-NEXT: |-VarDecl 0x{{.+}} parent 0x{{.+}} prev 0x{{.+}} <line:[[@LINE-25]]:3, col:34> col:14 TestVarTemplate 'const T' cinit instantiated_from 0x{{.+}}{{$}} // CHECK-NEXT: | |-NestedNameSpecifier TypeSpec 'S'{{$}} - // CHECK-NEXT: | `-InitListExpr 0x{{.+}} <col:32, col:34> 'void'{{$}} + // CHECK-NEXT: | `-InitListExpr 0x{{.+}} <col:32, col:34> 'void' explicit{{$}} // CHECK-NEXT: |-VarTemplateSpecialization 0x{{.+}} 'TestVarTemplate' 'const int'{{$}} // CHECK-NEXT: `-VarTemplateSpecialization 0x{{.+}} 'TestVarTemplate' 'const int'{{$}} @@ -744,7 +744,7 @@ namespace testCanonicalTemplate { // CHECK-NEXT: |-NestedNameSpecifier TypeSpec 'S'{{$}} // CHECK-NEXT: |-TemplateArgument type 'int'{{$}} // CHECK-NEXT: | `-BuiltinType 0x{{.+}} 'int'{{$}} - // CHECK-NEXT: `-InitListExpr 0x{{.+}} <col:32, col:34> 'int'{{$}} + // CHECK-NEXT: `-InitListExpr 0x{{.+}} <col:32, col:34> 'int' explicit{{$}} } template <class T> @@ -946,14 +946,14 @@ namespace TestConstexprVariableTemplateWithInitializer { // CHECK: VarTemplateDecl 0x{{.+}} <{{.+}}:[[@LINE-1]]:3, col:40> col:36 foo{{$}} // CHECK-NEXT: |-TemplateTypeParmDecl 0x{{.+}} <col:12, col:21> col:21 referenced typename depth 0 index 0 T{{$}} // CHECK-NEXT: `-VarDecl 0x{{.+}} <col:24, col:40> col:36 foo 'const T' constexpr listinit instantiated_from 0x{{.+}}{{$}} - // CHECK-NEXT: `-InitListExpr 0x{{.+}} <col:39, col:40> 'void'{{$}} + // CHECK-NEXT: `-InitListExpr 0x{{.+}} <col:39, col:40> 'void' explicit{{$}} template<typename T> constexpr int val{42}; // CHECK: VarTemplateDecl 0x{{.+}} <{{.+}}:[[@LINE-1]]:3, col:44> col:38 val{{$}} // CHECK-NEXT: |-TemplateTypeParmDecl 0x{{.+}} <col:12, col:21> col:21 typename depth 0 index 0 T{{$}} // CHECK-NEXT: `-VarDecl 0x{{.+}} <col:24, col:44> col:38 val 'const int' constexpr listinit instantiated_from 0x{{.+}}{{$}} // CHECK-NEXT: |-value: Int 42{{$}} - // CHECK-NEXT: `-InitListExpr 0x{{.+}} <col:41, col:44> 'int'{{$}} + // CHECK-NEXT: `-InitListExpr 0x{{.+}} <col:41, col:44> 'int' explicit{{$}} template <typename _Tp> struct in_place_type_t { @@ -965,7 +965,7 @@ namespace TestConstexprVariableTemplateWithInitializer { // CHECK: -VarTemplateDecl 0x{{.+}} <line:[[@LINE-2]]:3, line:[[@LINE-1]]:55> col:41 in_place_type{{$}} // CHECK-NEXT: |-TemplateTypeParmDecl 0x{{.+}} <line:[[@LINE-3]]:13, col:22> col:22 referenced typename depth 0 index 0 _Tp{{$}} // CHECK-NEXT: `-VarDecl 0x{{.+}} <line:[[@LINE-3]]:3, col:55> col:41 in_place_type 'const in_place_type_t<_Tp>' inline constexpr listinit instantiated_from 0x{{.+}}{{$}} - // CHECK-NEXT: `-InitListExpr 0x{{.+}} <col:54, col:55> 'void'{{$}} + // CHECK-NEXT: `-InitListExpr 0x{{.+}} <col:54, col:55> 'void' explicit{{$}} template <typename T> constexpr T call_init(0); // CHECK: -VarTemplateDecl 0x{{.+}} <line:[[@LINE-1]]:3, col:48> col:37 call_init{{$}} diff --git a/clang/test/AST/ast-dump-stmt.cpp b/clang/test/AST/ast-dump-stmt.cpp index 42c5f3b3498a4..6477e80ce1f21 100644 --- a/clang/test/AST/ast-dump-stmt.cpp +++ b/clang/test/AST/ast-dump-stmt.cpp @@ -98,9 +98,9 @@ void TestUnionInitList() { U us[3] = {1}; // CHECK: VarDecl {{.+}} <col:3, col:15> col:5 us 'U[3]' cinit -// CHECK-NEXT: `-InitListExpr {{.+}} <col:13, col:15> 'U[3]' -// CHECK-NEXT: |-array_filler: InitListExpr {{.+}} <col:15> 'U' field Field {{.+}} 'i' 'int' -// CHECK-NEXT: `-InitListExpr {{.+}} <col:14> 'U' field Field {{.+}} 'i' 'int' +// CHECK-NEXT: `-InitListExpr {{.+}} <col:13, col:15> 'U[3]' explicit +// CHECK-NEXT: |-array_filler: InitListExpr {{.+}} <col:15> 'U' field Field {{.+}} 'i' 'int' implicit +// CHECK-NEXT: `-InitListExpr {{.+}} <col:14> 'U' field Field {{.+}} 'i' 'int' implicit // CHECK-NEXT: `-IntegerLiteral {{.+}} <col:14> 'int' 1 } diff --git a/clang/test/CXX/drs/cwg2149.cpp b/clang/test/CXX/drs/cwg2149.cpp index 979f5ff6c0078..384485c39cac2 100644 --- a/clang/test/CXX/drs/cwg2149.cpp +++ b/clang/test/CXX/drs/cwg2149.cpp @@ -55,23 +55,23 @@ void f() { // via static_assert, even with constant folding enabled. // CXX98: VarDecl {{.+}} a 'X[2]' -// CXX98-NEXT: `-InitListExpr {{.+}} 'X[2]' -// CXX98-NEXT: |-InitListExpr {{.+}} 'X'{{$}} +// CXX98-NEXT: `-InitListExpr {{.+}} 'X[2]' explicit +// CXX98-NEXT: |-InitListExpr {{.+}} 'X' implicit{{$}} // CXX98-NEXT: | |-IntegerLiteral {{.+}} 'int' 1 // CXX98-NEXT: | |-IntegerLiteral {{.+}} 'int' 2 // CXX98-NEXT: | `-IntegerLiteral {{.+}} 'int' 3 -// CXX98-NEXT: `-InitListExpr {{.+}} 'X'{{$}} +// CXX98-NEXT: `-InitListExpr {{.+}} 'X' implicit{{$}} // CXX98-NEXT: |-IntegerLiteral {{.+}} 'int' 4 // CXX98-NEXT: |-IntegerLiteral {{.+}} 'int' 5 // CXX98-NEXT: `-IntegerLiteral {{.+}} 'int' 6 // CXX98: VarDecl {{.+}} b 'X[2]' -// CXX98-NEXT: `-InitListExpr {{.+}} 'X[2]' -// CXX98-NEXT: |-InitListExpr {{.+}} 'X'{{$}} +// CXX98-NEXT: `-InitListExpr {{.+}} 'X[2]' explicit +// CXX98-NEXT: |-InitListExpr {{.+}} 'X' explicit{{$}} // CXX98-NEXT: | |-IntegerLiteral {{.+}} 'int' 1 // CXX98-NEXT: | |-IntegerLiteral {{.+}} 'int' 2 // CXX98-NEXT: | `-IntegerLiteral {{.+}} 'int' 3 -// CXX98-NEXT: `-InitListExpr {{.+}} 'X'{{$}} +// CXX98-NEXT: `-InitListExpr {{.+}} 'X' explicit{{$}} // CXX98-NEXT: |-IntegerLiteral {{.+}} 'int' 4 // CXX98-NEXT: |-IntegerLiteral {{.+}} 'int' 5 // CXX98-NEXT: `-IntegerLiteral {{.+}} 'int' 6 diff --git a/clang/test/SemaCXX/compound-literal.cpp b/clang/test/SemaCXX/compound-literal.cpp index 4b975a0d73074..5062729c772c7 100644 --- a/clang/test/SemaCXX/compound-literal.cpp +++ b/clang/test/SemaCXX/compound-literal.cpp @@ -38,7 +38,7 @@ namespace brace_initializers { POD p = (POD){1, 2}; // CHECK-NOT: CXXBindTemporaryExpr {{.*}} 'brace_initializers::POD' // CHECK: CompoundLiteralExpr {{.*}} 'POD'{{$}} - // CHECK-NEXT: InitListExpr {{.*}} 'POD'{{$}} + // CHECK-NEXT: InitListExpr {{.*}} 'POD' explicit{{$}} // CHECK-NEXT: ConstantExpr {{.*}} // CHECK-NEXT: IntegerLiteral {{.*}} 1{{$}} // CHECK-NEXT: ConstantExpr {{.*}} @@ -49,14 +49,14 @@ namespace brace_initializers { // CHECK-NOT: CXXBindTemporaryExpr {{.*}} 'POD' // CHECK-NOT: ConstantExpr {{.*}} 'POD' // CHECK: CompoundLiteralExpr {{.*}} 'POD'{{$}} - // CHECK-NEXT: InitListExpr {{.*}} 'POD'{{$}} + // CHECK-NEXT: InitListExpr {{.*}} 'POD' explicit{{$}} // CHECK-NEXT: IntegerLiteral {{.*}} 1{{$}} // CHECK-NEXT: IntegerLiteral {{.*}} 2{{$}} (void)(HasDtor){1, 2}; // CHECK: CXXBindTemporaryExpr {{.*}} 'HasDtor' // CHECK-NEXT: CompoundLiteralExpr {{.*}} 'HasDtor'{{$}} - // CHECK-NEXT: InitListExpr {{.*}} 'HasDtor'{{$}} + // CHECK-NEXT: InitListExpr {{.*}} 'HasDtor' explicit{{$}} // CHECK-NEXT: IntegerLiteral {{.*}} 1{{$}} // CHECK-NEXT: IntegerLiteral {{.*}} 2{{$}} diff --git a/clang/test/SemaHLSL/Language/InitListAST.hlsl b/clang/test/SemaHLSL/Language/InitListAST.hlsl index 62acaf3046548..1919a96239f8b 100644 --- a/clang/test/SemaHLSL/Language/InitListAST.hlsl +++ b/clang/test/SemaHLSL/Language/InitListAST.hlsl @@ -147,8 +147,8 @@ TwoInts case6(TwoFloats TF4) { // conversions from a collection of scalar values, and structures. // CHECK-LABEL: Dumping case7 // CHECK: VarDecl {{.*}} used D1 'Doggo' nrvo cinit -// CHECK-NEXT: InitListExpr {{.*}} 'Doggo' -// CHECK-NEXT: InitListExpr {{.*}} 'int4':'vector<int, 4>' +// CHECK-NEXT: InitListExpr {{.*}} 'Doggo' explicit +// CHECK-NEXT: InitListExpr {{.*}} 'int4':'vector<int, 4>' implicit // CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue> // CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue .Z {{.*}} // CHECK-NEXT: DeclRefExpr {{.*}} 'TwoInts' lvalue ParmVar {{.*}} 'TI1' 'TwoInts' @@ -166,8 +166,8 @@ TwoInts case6(TwoFloats TF4) { // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating> // CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue> // CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'Val' 'int' -// CHECK-NEXT: InitListExpr {{.*}} 'float4[2]' -// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>' +// CHECK-NEXT: InitListExpr {{.*}} 'float4[2]' implicit +// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>' implicit // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue> // CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .X {{.*}} // CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF1' 'TwoFloats' @@ -180,7 +180,7 @@ TwoInts case6(TwoFloats TF4) { // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue> // CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .Y {{.*}} // CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF2' 'TwoFloats' -// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>' +// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>' implicit // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue> // CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .X {{.*}} // CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF3' 'TwoFloats' @@ -203,8 +203,8 @@ Doggo case7(TwoInts TI1, TwoInts TI2, int Val, TwoFloats TF1, TwoFloats TF2, // significantly different element types and grouping. // CHECK-LABEL: Dumping case8 // CHECK: VarDecl {{.*}} used A1 'AnimalBits' nrvo cinit -// CHECK-NEXT: InitListExpr {{.*}} 'AnimalBits' -// CHECK-NEXT: InitListExpr {{.*}} 'int[4]' +// CHECK-NEXT: InitListExpr {{.*}} 'AnimalBits' explicit +// CHECK-NEXT: InitListExpr {{.*}} 'int[4]' implicit // CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue> // CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent // CHECK-NEXT: MemberExpr {{.*}} 'int4':'vector<int, 4>' lvalue .LegState {{.*}} @@ -233,7 +233,7 @@ Doggo case7(TwoInts TI1, TwoInts TI2, int Val, TwoFloats TF1, TwoFloats TF2, // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue> // CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .HairCount {{.*}} // CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo' -// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>' +// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>' implicit // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue> // CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent // CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue @@ -266,7 +266,7 @@ Doggo case7(TwoInts TI1, TwoInts TI2, int Val, TwoFloats TF1, TwoFloats TF2, // CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo' // CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 0 // CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 3 -// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>' +// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>' implicit // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue> // CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent // CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue @@ -836,8 +836,8 @@ Zoo case9(Doggo D1, AnimalBits A1) { // Case 10: Initialize an object with a base class from two objects. // CHECK-LABEL: Dumping case10 // CHECK: | `-VarDecl {{.*}} used FF1 'FourFloats' nrvo cinit -// CHECK-NEXT: InitListExpr {{.*}} 'FourFloats' -// CHECK-NEXT: InitListExpr {{.*}} 'TwoFloats' +// CHECK-NEXT: InitListExpr {{.*}} 'FourFloats' explicit +// CHECK-NEXT: InitListExpr {{.*}} 'TwoFloats' implicit // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue> // CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .X {{.*}} // CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF1' 'TwoFloats' diff --git a/clang/unittests/AST/ASTExprTest.cpp b/clang/unittests/AST/ASTExprTest.cpp index adaceb76de8b4..d699c4e486d87 100644 --- a/clang/unittests/AST/ASTExprTest.cpp +++ b/clang/unittests/AST/ASTExprTest.cpp @@ -14,6 +14,8 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/IgnoreExpr.h" +#include "clang/AST/OpenACCClause.h" +#include "clang/AST/StmtOpenACC.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Tooling/Tooling.h" #include "gtest/gtest.h" @@ -21,10 +23,17 @@ using namespace clang; using clang::ast_matchers::cxxRecordDecl; +using clang::ast_matchers::forStmt; +using clang::ast_matchers::has; using clang::ast_matchers::hasName; +using clang::ast_matchers::initListExpr; using clang::ast_matchers::match; +using clang::ast_matchers::selectFirst; +using clang::ast_matchers::stmt; +using clang::ast_matchers::substNonTypeTemplateParmExpr; using clang::ast_matchers::varDecl; using clang::tooling::buildASTFromCode; +using clang::tooling::buildASTFromCodeWithArgs; static IntegerLiteral *createIntLiteral(ASTContext &Ctx, uint32_t Value) { const int numBits = 32; @@ -88,14 +97,16 @@ TEST(ASTExpr, InitListIsConstantInitialized) { const CXXRecordDecl *Foo = getCXXRecordDeclNode(AST.get(), "Foo"); SourceLocation Loc{}; - InitListExpr *BaseInit = new (Ctx) InitListExpr(Ctx, Loc, {}, Loc); + InitListExpr *BaseInit = + new (Ctx) InitListExpr(Ctx, Loc, {}, Loc, /*isExplicit=*/true); BaseInit->setType(Ctx.getCanonicalTagType(Empty)); Expr *Exprs[3] = { BaseInit, createIntLiteral(Ctx, 13), createIntLiteral(Ctx, 42), }; - InitListExpr *FooInit = new (Ctx) InitListExpr(Ctx, Loc, Exprs, Loc); + InitListExpr *FooInit = + new (Ctx) InitListExpr(Ctx, Loc, Exprs, Loc, /*isExplicit=*/true); FooInit->setType(Ctx.getCanonicalTagType(Foo)); EXPECT_TRUE(FooInit->isConstantInitializer(Ctx, false)); @@ -108,3 +119,235 @@ TEST(ASTExpr, InitListIsConstantInitialized) { (void)FooInit->updateInit(Ctx, 2, Ref); EXPECT_FALSE(FooInit->isConstantInitializer(Ctx, false)); } + +struct NestedInitListParams { + const char *Code; + bool InnerIsExplicit; +} NestedInitListParamArray[] = { + {R"cpp( + struct Outer { + struct { int i; } inner; + } o = {}; + )cpp", + false}, + {R"cpp( + struct Outer { + struct { int i; } inner; + } o = {1}; + )cpp", + false}, + {R"cpp( + struct Outer { + struct { int i; } inner; + } o = {{1}}; + )cpp", + true}, + {R"cpp( + struct Outer { + struct { + int i; + int j; + } inner; + int k; + } o = {1, 2, 3}; + )cpp", + false}, + {R"cpp( + struct Outer { + struct { + int i; + int j; + } inner; + int k; + } o = {{1, 2}, 3}; + )cpp", + true}, +}; + +class NestedInitListTest : public testing::TestWithParam<NestedInitListParams> { +}; + +TEST_P(NestedInitListTest, IsExplicit) { + auto AST = buildASTFromCode(GetParam().Code); + const auto *OuterList = selectFirst<InitListExpr>( + "initList", match(initListExpr().bind("initList"), AST->getASTContext())); + ASSERT_NE(OuterList, nullptr); + EXPECT_TRUE(OuterList->isExplicit()); + ASSERT_FALSE(OuterList->isSyntacticForm()); + EXPECT_TRUE(OuterList->getSyntacticForm()->isExplicit()); + ASSERT_TRUE(OuterList->getNumInits() >= 1); + const auto *InnerList = dyn_cast<InitListExpr>(OuterList->getInit(0)); + ASSERT_NE(InnerList, nullptr); + EXPECT_EQ(InnerList->isExplicit(), GetParam().InnerIsExplicit); + if (!InnerList->isSyntacticForm()) { + EXPECT_EQ(InnerList->getSyntacticForm()->isExplicit(), + GetParam().InnerIsExplicit); + } +} + +INSTANTIATE_TEST_SUITE_P(NestedInitLists, NestedInitListTest, + testing::ValuesIn(NestedInitListParamArray)); + +TEST(ASTExpr, RewrappedExplicitInitList) { + auto AST = buildASTFromCode(R"cpp( + const int& x = {1}; + )cpp"); + const auto *InitList = selectFirst<InitListExpr>( + "initList", match(initListExpr().bind("initList"), AST->getASTContext())); + ASSERT_NE(InitList, nullptr); + EXPECT_TRUE(InitList->isExplicit()); +} + +TEST(ASTExpr, DesignatedInitImplicitList) { + auto AST = buildASTFromCodeWithArgs(R"c( + struct Inner { + int i, j; + }; + struct Outer { + struct Inner inner; + } o = { .inner.i = 1 }; + )c", + {"-xc"}); + const auto *OuterList = selectFirst<InitListExpr>( + "initList", match(initListExpr().bind("initList"), AST->getASTContext())); + ASSERT_NE(OuterList, nullptr); + EXPECT_TRUE(OuterList->isExplicit()); + ASSERT_FALSE(OuterList->isSyntacticForm()); + EXPECT_TRUE(OuterList->getSyntacticForm()->isExplicit()); + ASSERT_TRUE(OuterList->getNumInits() == 1); + const auto *InnerList = dyn_cast<InitListExpr>(OuterList->getInit(0)); + EXPECT_TRUE(InnerList->isSemanticForm() && InnerList->isSyntacticForm()); + EXPECT_FALSE(InnerList->isExplicit()); +} + +TEST(ASTExpr, DesignatedInitUpdateImplicitList) { + auto AST = buildASTFromCodeWithArgs(R"c( + struct Inner { + int i, j; + }; + struct Outer { + struct Inner inner; + } o = { (struct Inner){}, .inner.j = 1 }; + )c", + {"-xc", "-Wno-initializer-overrides"}); + const auto *OuterList = selectFirst<InitListExpr>( + "initList", match(initListExpr().bind("initList"), AST->getASTContext())); + ASSERT_NE(OuterList, nullptr); + ASSERT_EQ(OuterList->getNumInits(), 1u); + const auto *UpdateExpr = + dyn_cast<DesignatedInitUpdateExpr>(OuterList->getInit(0)); + const InitListExpr *UpdaterInit = UpdateExpr->getUpdater(); + EXPECT_FALSE(UpdaterInit->isExplicit()); +} + +TEST(ASTExpr, OpenCLVectorInitList) { + auto AST = buildASTFromCodeWithArgs(R"c( + void Fn() { + (void)(int __attribute__((ext_vector_type(2))))(1,2); + } + )c", + {"-xcl"}); + const auto *List = selectFirst<InitListExpr>( + "initList", match(initListExpr().bind("initList"), AST->getASTContext())); + EXPECT_FALSE(List->isExplicit()); +} + +TEST(ASTExpr, TransparentUnionInitList) { + auto AST = buildASTFromCodeWithArgs(R"c( + union U { + int i; + } __attribute__((transparent_union)); + void TakeUnion(union U); + void Fn() { + TakeUnion(1); + } + )c", + {"-xc"}); + const auto *List = selectFirst<InitListExpr>( + "initList", match(initListExpr().bind("initList"), AST->getASTContext())); + EXPECT_FALSE(List->isExplicit()); +} + +TEST(ASTExpr, ComplexTplArgInitList) { + auto AST = buildASTFromCodeWithArgs(R"cpp( + template <double _Complex C> + void TplFn() { + (void)C; + } + void Fn() { + TplFn<1.0 + 2.0i>(); + } + )cpp", + {"-std=c++20"}); + const auto *SNTTP = selectFirst<SubstNonTypeTemplateParmExpr>( + "SNTTP", match(substNonTypeTemplateParmExpr().bind("SNTTP"), + AST->getASTContext())); + const auto *List = dyn_cast<InitListExpr>(SNTTP->getReplacement()); + ASSERT_NE(List, nullptr); + EXPECT_FALSE(List->isExplicit()); +} + +class OpenACCReductionInitListTest + : public testing::TestWithParam<const char *> {}; + +TEST_P(OpenACCReductionInitListTest, ImplicitInit) { + auto AST = buildASTFromCodeWithArgs(GetParam(), {"-fopenacc"}); + const auto *ACCConstruct = selectFirst<OpenACCConstructStmt>( + "accConstruct", + match(stmt(has(forStmt())).bind("accConstruct"), AST->getASTContext())); + ASSERT_NE(ACCConstruct, nullptr); + ArrayRef<const OpenACCClause *> Clauses = ACCConstruct->clauses(); + ASSERT_EQ(Clauses.size(), 1u); + const auto *ReductionClause = dyn_cast<OpenACCReductionClause>(Clauses[0]); + ASSERT_NE(ReductionClause, nullptr); + ArrayRef<OpenACCReductionRecipe> Recipes = ReductionClause->getRecipes(); + ASSERT_EQ(Recipes.size(), 1u); + const auto *List = dyn_cast<InitListExpr>(Recipes[0].AllocaDecl->getInit()); + ASSERT_NE(List, nullptr); + EXPECT_FALSE(List->isExplicit()); +} + +INSTANTIATE_TEST_SUITE_P(OpenACCReductionInitLists, + OpenACCReductionInitListTest, + testing::Values( + R"cpp( + void Fn() { + int sum = 0; + #pragma acc parallel loop reduction(+:sum) + for (int i = 0; i < 5; ++i) + sum += i; + } +)cpp", + R"cpp( + void Fn() { + unsigned res = ~0u; + #pragma acc parallel loop reduction(&:res) + for (int i = 0; i < 5; ++i) + res &= i; + } +)cpp")); + +TEST(ASTExpr, OpenACCFirstPrivateInitList) { + auto AST = buildASTFromCodeWithArgs(R"cpp( + void Fn() { + int arr[2] = {}; + #pragma acc parallel loop firstprivate(arr) + for (int i = 0; i < 5; ++i) + (void)(arr[0] - arr[1]); + } + )cpp", + {"-fopenacc"}); + const auto *ACCConstruct = selectFirst<OpenACCConstructStmt>( + "accConstruct", + match(stmt(has(forStmt())).bind("accConstruct"), AST->getASTContext())); + ASSERT_NE(ACCConstruct, nullptr); + ArrayRef<const OpenACCClause *> Clauses = ACCConstruct->clauses(); + ASSERT_EQ(Clauses.size(), 1u); + const auto *FirstPrivate = dyn_cast<OpenACCFirstPrivateClause>(Clauses[0]); + ASSERT_NE(FirstPrivate, nullptr); + ArrayRef<OpenACCFirstPrivateRecipe> Recipes = FirstPrivate->getInitRecipes(); + ASSERT_EQ(Recipes.size(), 1u); + const auto *List = dyn_cast<InitListExpr>(Recipes[0].AllocaDecl->getInit()); + ASSERT_NE(List, nullptr); + EXPECT_FALSE(List->isExplicit()); +} diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index f96f2a8429b89..4ba312556aac0 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -521,19 +521,21 @@ TEST_P(ImportExpr, ImportPredefinedExpr) { TEST_P(ImportExpr, ImportInitListExpr) { MatchVerifier<Decl> Verifier; - testImport("void declToImport() {" - " struct point { double x; double y; };" - " point ptarray[10] = { [2].y = 1.0, [2].x = 2.0," - " [0].x = 1.0 }; }", - Lang_CXX03, "", Lang_CXX03, Verifier, - functionDecl(hasDescendant(initListExpr( - has(cxxConstructExpr(requiresZeroInitialization())), - has(initListExpr( - hasType(asString("point")), has(floatLiteral(equals(1.0))), - has(implicitValueInitExpr(hasType(asString("double")))))), - has(initListExpr(hasType(asString("point")), - has(floatLiteral(equals(2.0))), - has(floatLiteral(equals(1.0))))))))); + testImport( + "void declToImport() {" + " struct point { double x; double y; };" + " point ptarray[10] = { [2].y = 1.0, [2].x = 2.0," + " [0].x = 1.0 }; }", + Lang_CXX03, "", Lang_CXX03, Verifier, + functionDecl(hasDescendant(initListExpr( + isExplicit(), has(cxxConstructExpr(requiresZeroInitialization())), + has(initListExpr( + unless(isExplicit()), hasType(asString("point")), + has(floatLiteral(equals(1.0))), + has(implicitValueInitExpr(hasType(asString("double")))))), + has(initListExpr(unless(isExplicit()), hasType(asString("point")), + has(floatLiteral(equals(2.0))), + has(floatLiteral(equals(1.0))))))))); } const internal::VariadicDynCastAllOfMatcher<Expr, CXXDefaultInitExpr> >From 1b370ab0e85a0b3b09e55132032ef058e513c8bd Mon Sep 17 00:00:00 2001 From: Bolshakov <[email protected]> Date: Mon, 4 May 2026 20:40:17 +0300 Subject: [PATCH 2/3] amend! [clang] Make `InitListExpr::isExplicit()` work [clang] Make `InitListExpr::isExplicit()` work The main goal of this change is to be able to use `isExplicit()` check in the IWYU tool. Consider the following: struct Inner {}; struct Outer { Inner inner; }; const Outer& refOuter = {}; Here, Clang generates `InitListExpr` child node for the implicit `Inner` initialization under the `InitListExpr` node corresponding to the initializer of `refOuter`. IWYU should require the header containing `Outer` definition for the initializer, but not the header for `Inner` because it should be already provided by `Outer`. 'IsExplicit' flag is copied from a template instantiation pattern into its instantiations although they are implicit because it makes sense for IWYU at least. (After all, instantiated declarations refer to the pattern explicitly written in the source.) `isImplicit()` AST matcher has been extended to support `InitListExpr`s. This is an NFC from the point of view of users of the Clang standalone executable (except the change in AST dumping), but a functional change for those who use Clang as a library. --- clang/docs/LibASTMatchersReference.html | 2 +- clang/include/clang/ASTMatchers/ASTMatchers.h | 13 +++++--- clang/lib/Sema/SemaInit.cpp | 9 +++--- clang/unittests/AST/ASTImporterTest.cpp | 30 +++++++++---------- 4 files changed, 29 insertions(+), 25 deletions(-) diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index b13eec72f9e3b..9f9d4223bb50a 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -3322,7 +3322,7 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2> <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('isExplicit0')"><a name="isExplicit0Anchor">isExplicit</a></td><td></td></tr> <tr><td colspan="4" class="doc" id="isExplicit0"><pre>Matches constructor, conversion function, and deduction guide declarations that have an explicit specifier if this explicit specifier is resolved to -true. Also matches explicitly written initializer list expressions. +true. Given template<bool b> diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index ffceb9269fc6e..2b39edef3c162 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -95,6 +95,7 @@ #include <limits> #include <optional> #include <string> +#include <type_traits> #include <utility> #include <vector> @@ -775,8 +776,12 @@ AST_MATCHER_P(ClassTemplateSpecializationDecl, hasSpecializedTemplate, /// implicit default/copy constructors). AST_POLYMORPHIC_MATCHER(isImplicit, AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Attr, - LambdaCapture)) { - return Node.isImplicit(); + LambdaCapture, + InitListExpr)) { + if constexpr (std::is_same_v<NodeType, InitListExpr>) + return !Node.isExplicit(); + else + return Node.isImplicit(); } /// Matches templateSpecializationTypes, class template specializations, @@ -8122,7 +8127,7 @@ AST_MATCHER(CXXConstructorDecl, isDelegatingConstructor) { /// Matches constructor, conversion function, and deduction guide declarations /// that have an explicit specifier if this explicit specifier is resolved to -/// true. Also matches explicitly written initializer list expressions. +/// true. /// /// Given /// \code @@ -8144,7 +8149,7 @@ AST_MATCHER(CXXConstructorDecl, isDelegatingConstructor) { /// cxxDeductionGuideDecl(isExplicit()) will match #6, but not #5. AST_POLYMORPHIC_MATCHER(isExplicit, AST_POLYMORPHIC_SUPPORTED_TYPES( CXXConstructorDecl, CXXConversionDecl, - CXXDeductionGuideDecl, InitListExpr)) { + CXXDeductionGuideDecl)) { return Node.isExplicit(); } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 2521684212b91..eaf6fa78b79c2 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -3565,9 +3565,9 @@ InitListExpr *InitListChecker::createInitListExpr(QualType CurrentObjectType, SourceRange InitRange, unsigned ExpectedNumInits, bool IsExplicit) { - InitListExpr *Result = new (SemaRef.Context) - InitListExpr(SemaRef.Context, InitRange.getBegin(), {}, - InitRange.getEnd(), /*isExplicit=*/IsExplicit); + InitListExpr *Result = + new (SemaRef.Context) InitListExpr(SemaRef.Context, InitRange.getBegin(), + {}, InitRange.getEnd(), IsExplicit); QualType ResultType = CurrentObjectType; if (!ResultType->isArrayType()) @@ -8447,10 +8447,9 @@ ExprResult InitializationSequence::Perform(Sema &S, case SK_RewrapInitList: { Expr *E = CurInit.get(); InitListExpr *Syntactic = Step->WrappingSyntacticList; - assert(Syntactic->isExplicit()); InitListExpr *ILE = new (S.Context) InitListExpr(S.Context, Syntactic->getLBraceLoc(), E, - Syntactic->getRBraceLoc(), /*isExplicit=*/true); + Syntactic->getRBraceLoc(), Syntactic->isExplicit()); ILE->setSyntacticForm(Syntactic); ILE->setType(E->getType()); ILE->setValueKind(E->getValueKind()); diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 4ba312556aac0..47c8fa384f687 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -521,21 +521,21 @@ TEST_P(ImportExpr, ImportPredefinedExpr) { TEST_P(ImportExpr, ImportInitListExpr) { MatchVerifier<Decl> Verifier; - testImport( - "void declToImport() {" - " struct point { double x; double y; };" - " point ptarray[10] = { [2].y = 1.0, [2].x = 2.0," - " [0].x = 1.0 }; }", - Lang_CXX03, "", Lang_CXX03, Verifier, - functionDecl(hasDescendant(initListExpr( - isExplicit(), has(cxxConstructExpr(requiresZeroInitialization())), - has(initListExpr( - unless(isExplicit()), hasType(asString("point")), - has(floatLiteral(equals(1.0))), - has(implicitValueInitExpr(hasType(asString("double")))))), - has(initListExpr(unless(isExplicit()), hasType(asString("point")), - has(floatLiteral(equals(2.0))), - has(floatLiteral(equals(1.0))))))))); + testImport("void declToImport() {" + " struct point { double x; double y; };" + " point ptarray[10] = { [2].y = 1.0, [2].x = 2.0," + " [0].x = 1.0 }; }", + Lang_CXX03, "", Lang_CXX03, Verifier, + functionDecl(hasDescendant(initListExpr( + unless(isImplicit()), + has(cxxConstructExpr(requiresZeroInitialization())), + has(initListExpr( + isImplicit(), hasType(asString("point")), + has(floatLiteral(equals(1.0))), + has(implicitValueInitExpr(hasType(asString("double")))))), + has(initListExpr(isImplicit(), hasType(asString("point")), + has(floatLiteral(equals(2.0))), + has(floatLiteral(equals(1.0))))))))); } const internal::VariadicDynCastAllOfMatcher<Expr, CXXDefaultInitExpr> >From 7a3ec1a43438d83c3df3dbc5a8f4be65a23fb839 Mon Sep 17 00:00:00 2001 From: Bolshakov <[email protected]> Date: Thu, 7 May 2026 11:33:33 +0300 Subject: [PATCH 3/3] fixup! [clang] Make `InitListExpr::isExplicit()` work --- clang/docs/LibASTMatchersReference.html | 58 +++++++++++++++++++ clang/include/clang/AST/Expr.h | 4 +- clang/include/clang/ASTMatchers/ASTMatchers.h | 17 ++++++ 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index 9f9d4223bb50a..679463fb4b01a 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -3057,6 +3057,19 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2> <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Attr.html">Attr</a>></td><td class="name" onclick="toggle('isImplicit1')"><a name="isImplicit1Anchor">isImplicit</a></td><td></td></tr> <tr><td colspan="4" class="doc" id="isImplicit1"><pre>Matches an entity that has been implicitly added by the compiler (e.g. implicit default/copy constructors). + +For example, given: + int i, j; + auto l = [&, j]() { return i; }; +lambdaCapture(isImplicit()) + matches the capture of i but not of j. +Given: + struct Outer { + struct Inner {} inner; + } outer = {}; +initListExpr(isImplicit()) + matches the implicitly added Inner initializer inside InitListExpr node + for the explicit initializer of Outer. </pre></td></tr> @@ -4304,6 +4317,19 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2> <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isImplicit0')"><a name="isImplicit0Anchor">isImplicit</a></td><td></td></tr> <tr><td colspan="4" class="doc" id="isImplicit0"><pre>Matches an entity that has been implicitly added by the compiler (e.g. implicit default/copy constructors). + +For example, given: + int i, j; + auto l = [&, j]() { return i; }; +lambdaCapture(isImplicit()) + matches the capture of i but not of j. +Given: + struct Outer { + struct Inner {} inner; + } outer = {}; +initListExpr(isImplicit()) + matches the implicitly added Inner initializer inside InitListExpr node + for the explicit initializer of Outer. </pre></td></tr> @@ -4983,6 +5009,25 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2> </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1InitListExpr.html">InitListExpr</a>></td><td class="name" onclick="toggle('isImplicit3')"><a name="isImplicit3Anchor">isImplicit</a></td><td></td></tr> +<tr><td colspan="4" class="doc" id="isImplicit3"><pre>Matches an entity that has been implicitly added by the compiler (e.g. +implicit default/copy constructors). + +For example, given: + int i, j; + auto l = [&, j]() { return i; }; +lambdaCapture(isImplicit()) + matches the capture of i but not of j. +Given: + struct Outer { + struct Inner {} inner; + } outer = {}; +initListExpr(isImplicit()) + matches the implicitly added Inner initializer inside InitListExpr node + for the explicit initializer of Outer. +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>></td><td class="name" onclick="toggle('equals6')"><a name="equals6Anchor">equals</a></td><td>bool Value</td></tr> <tr><td colspan="4" class="doc" id="equals6"><pre></pre></td></tr> @@ -5040,6 +5085,19 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2> <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1LambdaCapture.html">LambdaCapture</a>></td><td class="name" onclick="toggle('isImplicit2')"><a name="isImplicit2Anchor">isImplicit</a></td><td></td></tr> <tr><td colspan="4" class="doc" id="isImplicit2"><pre>Matches an entity that has been implicitly added by the compiler (e.g. implicit default/copy constructors). + +For example, given: + int i, j; + auto l = [&, j]() { return i; }; +lambdaCapture(isImplicit()) + matches the capture of i but not of j. +Given: + struct Outer { + struct Inner {} inner; + } outer = {}; +initListExpr(isImplicit()) + matches the implicitly added Inner initializer inside InitListExpr node + for the explicit initializer of Outer. </pre></td></tr> diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 7ef7b3d030d43..ed3c1a912afc5 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -5328,7 +5328,9 @@ class InitListExpr : public Expr { /// Build an empty initializer list. explicit InitListExpr(EmptyShell Empty) - : Expr(InitListExprClass, Empty), AltForm(nullptr, true) { } + : Expr(InitListExprClass, Empty), AltForm(nullptr, true) { + InitListExprBits.IsExplicit = false; + } unsigned getNumInits() const { return InitExprs.size(); } diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 2b39edef3c162..bc0f35898a2c9 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -774,6 +774,23 @@ AST_MATCHER_P(ClassTemplateSpecializationDecl, hasSpecializedTemplate, /// Matches an entity that has been implicitly added by the compiler (e.g. /// implicit default/copy constructors). +/// +/// For example, given: +/// \code +/// int i, j; +/// auto l = [&, j]() { return i; }; +/// \endcode +/// lambdaCapture(isImplicit()) +/// matches the capture of i but not of j. +/// Given: +/// \code +/// struct Outer { +/// struct Inner {} inner; +/// } outer = {}; +/// \endcode +/// initListExpr(isImplicit()) +/// matches the implicitly added Inner initializer inside InitListExpr node +/// for the explicit initializer of Outer. AST_POLYMORPHIC_MATCHER(isImplicit, AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Attr, LambdaCapture, _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
