diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/Expr.cpp | 29 | ||||
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 3 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprAgg.cpp | 16 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprConstant.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 79 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 2 |
8 files changed, 113 insertions, 34 deletions
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index e43a9c53d90..776a7f996d0 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1864,6 +1864,24 @@ bool InitListExpr::isStringLiteralInit() const { return isa<StringLiteral>(Init) || isa<ObjCEncodeExpr>(Init); } +bool InitListExpr::isTransparent() const { + assert(isSemanticForm() && "syntactic form never semantically transparent"); + + // A glvalue InitListExpr is always just sugar. + if (isGLValue()) { + assert(getNumInits() == 1 && "multiple inits in glvalue init list"); + return true; + } + + // Otherwise, we're sugar if and only if we have exactly one initializer that + // is of the same type. + if (getNumInits() != 1 || !getInit(0)) + return false; + + return getType().getCanonicalType() == + getInit(0)->getType().getCanonicalType(); +} + SourceLocation InitListExpr::getLocStart() const { if (InitListExpr *SyntacticForm = getSyntacticForm()) return SyntacticForm->getLocStart(); @@ -2246,12 +2264,15 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, // effects (e.g. a placement new with an uninitialized POD). case CXXDeleteExprClass: return false; + case MaterializeTemporaryExprClass: + return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr() + ->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); case CXXBindTemporaryExprClass: - return (cast<CXXBindTemporaryExpr>(this) - ->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx)); + return cast<CXXBindTemporaryExpr>(this)->getSubExpr() + ->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); case ExprWithCleanupsClass: - return (cast<ExprWithCleanups>(this) - ->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx)); + return cast<ExprWithCleanups>(this)->getSubExpr() + ->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); } } diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 14214bdd0a6..fa5cb8cd732 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -5670,6 +5670,9 @@ bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) { } bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { + if (E->isTransparent()) + return Visit(E->getInit(0)); + const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 6db668204f5..bd21a868663 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -3522,7 +3522,7 @@ LValue CodeGenFunction::EmitInitListLValue(const InitListExpr *E) { return EmitAggExprToLValue(E); // An lvalue initializer list must be initializing a reference. - assert(E->getNumInits() == 1 && "reference init with multiple values"); + assert(E->isTransparent() && "non-transparent glvalue init list"); return EmitLValue(E->getInit(0)); } diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index f51330c8b19..98f476efe93 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -1145,15 +1145,15 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { if (E->hadArrayRangeDesignator()) CGF.ErrorUnsupported(E, "GNU array range designator extension"); + if (E->isTransparent()) + return Visit(E->getInit(0)); + AggValueSlot Dest = EnsureSlot(E->getType()); LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType()); // Handle initialization of an array. if (E->getType()->isArrayType()) { - if (E->isStringLiteralInit()) - return Visit(E->getInit(0)); - QualType elementType = CGF.getContext().getAsArrayType(E->getType())->getElementType(); @@ -1162,16 +1162,6 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { return; } - if (E->getType()->isAtomicType()) { - // An _Atomic(T) object can be list-initialized from an expression - // of the same type. - assert(E->getNumInits() == 1 && - CGF.getContext().hasSameUnqualifiedType(E->getInit(0)->getType(), - E->getType()) && - "unexpected list initialization for atomic object"); - return Visit(E->getInit(0)); - } - assert(E->getType()->isRecordType() && "Only support structs/unions here!"); // Do struct initialization; this code just sets each individual member diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index cf834564c0a..27c8386ee46 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -778,9 +778,6 @@ public: } llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) { - if (ILE->isStringLiteralInit()) - return Visit(ILE->getInit(0)); - llvm::ArrayType *AType = cast<llvm::ArrayType>(ConvertType(ILE->getType())); llvm::Type *ElemTy = AType->getElementType(); @@ -845,6 +842,9 @@ public: } llvm::Constant *VisitInitListExpr(InitListExpr *ILE) { + if (ILE->isTransparent()) + return Visit(ILE->getInit(0)); + if (ILE->getType()->isArrayType()) return EmitArrayInitialization(ILE); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 28ccd607507..262235a9fa9 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6836,6 +6836,16 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) { return E; E = Res.get(); } + + // C++1z: + // If the expression is a prvalue after this optional conversion, the + // temporary materialization conversion is applied. + // + // We skip this step: IR generation is able to synthesize the storage for + // itself in the aggregate case, and adding the extra node to the AST is + // just clutter. + // FIXME: We don't emit lifetime markers for the temporaries due to this. + // FIXME: Do any other AST consumers care about this? return E; } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index c21dbc18b93..a0ea8e1ba03 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -3546,8 +3546,14 @@ static void TryConstructorInitialization(Sema &S, InitializationSequence &Sequence, bool IsListInit = false, bool IsInitListCopy = false) { - assert((!IsListInit || (Args.size() == 1 && isa<InitListExpr>(Args[0]))) && - "IsListInit must come with a single initializer list argument."); + assert(((!IsListInit && !IsInitListCopy) || + (Args.size() == 1 && isa<InitListExpr>(Args[0]))) && + "IsListInit/IsInitListCopy must come with a single initializer list " + "argument."); + InitListExpr *ILE = + (IsListInit || IsInitListCopy) ? cast<InitListExpr>(Args[0]) : nullptr; + MultiExprArg UnwrappedArgs = + ILE ? MultiExprArg(ILE->getInits(), ILE->getNumInits()) : Args; // The type we're constructing needs to be complete. if (!S.isCompleteType(Kind.getLocation(), DestType)) { @@ -3555,6 +3561,35 @@ static void TryConstructorInitialization(Sema &S, return; } + // C++1z [dcl.init]p17: + // - If the initializer expression is a prvalue and the cv-unqualified + // version of the source type is the same class as the class of the + // destination, the initializer expression is used to initialize the + // destination object. + // Per DR (no number yet), this does not apply when initializing a base + // class or delegating to another constructor from a mem-initializer. + if (S.getLangOpts().CPlusPlus1z && + Entity.getKind() != InitializedEntity::EK_Base && + Entity.getKind() != InitializedEntity::EK_Delegating && + UnwrappedArgs.size() == 1 && UnwrappedArgs[0]->isRValue() && + S.Context.hasSameUnqualifiedType(UnwrappedArgs[0]->getType(), DestType)) { + // Convert qualifications if necessary. + QualType InitType = UnwrappedArgs[0]->getType(); + ImplicitConversionSequence ICS; + ICS.setStandard(); + ICS.Standard.setAsIdentityConversion(); + ICS.Standard.setFromType(InitType); + ICS.Standard.setAllToTypes(InitType); + if (!S.Context.hasSameType(InitType, DestType)) { + ICS.Standard.Third = ICK_Qualification; + ICS.Standard.setToType(2, DestType); + } + Sequence.AddConversionSequenceStep(ICS, DestType); + if (ILE) + Sequence.RewrapReferenceInitList(DestType, ILE); + return; + } + const RecordType *DestRecordType = DestType->getAs<RecordType>(); assert(DestRecordType && "Constructor initialization requires record type"); CXXRecordDecl *DestRecordDecl @@ -3588,20 +3623,16 @@ static void TryConstructorInitialization(Sema &S, // constructors of the class T and the argument list consists of the // initializer list as a single argument. if (IsListInit) { - InitListExpr *ILE = cast<InitListExpr>(Args[0]); AsInitializerList = true; // If the initializer list has no elements and T has a default constructor, // the first phase is omitted. - if (ILE->getNumInits() != 0 || !DestRecordDecl->hasDefaultConstructor()) + if (!(UnwrappedArgs.empty() && DestRecordDecl->hasDefaultConstructor())) Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, CandidateSet, Ctors, Best, CopyInitialization, AllowExplicit, /*OnlyListConstructor=*/true, IsListInit); - - // Time to unwrap the init list. - Args = MultiExprArg(ILE->getInits(), ILE->getNumInits()); } // C++11 [over.match.list]p1: @@ -3611,7 +3642,7 @@ static void TryConstructorInitialization(Sema &S, // elements of the initializer list. if (Result == OR_No_Viable_Function) { AsInitializerList = false; - Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, + Result = ResolveConstructorOverload(S, Kind.getLocation(), UnwrappedArgs, CandidateSet, Ctors, Best, CopyInitialization, AllowExplicit, /*OnlyListConstructors=*/false, @@ -3821,8 +3852,8 @@ static void TryListInitialization(Sema &S, QualType InitType = InitList->getInit(0)->getType(); if (S.Context.hasSameUnqualifiedType(InitType, DestType) || S.IsDerivedFrom(InitList->getLocStart(), InitType, DestType)) { - Expr *InitAsExpr = InitList->getInit(0); - TryConstructorInitialization(S, Entity, Kind, InitAsExpr, DestType, + Expr *InitListAsExpr = InitList; + TryConstructorInitialization(S, Entity, Kind, InitListAsExpr, DestType, Sequence, /*InitListSyntax*/ false, /*IsInitListCopy*/ true); return; @@ -4332,16 +4363,21 @@ static void TryReferenceInitializationCore(Sema &S, } // - If the initializer expression + // C++14-and-before: // - is an xvalue, class prvalue, array prvalue, or function lvalue and // "cv1 T1" is reference-compatible with "cv2 T2" + // C++1z: + // - is an rvalue or function lvalue and "cv1 T1" is reference-compatible + // with "cv2 T2" // Note: functions are handled below. if (!T1Function && (RefRelationship == Sema::Ref_Compatible || (Kind.isCStyleOrFunctionalCast() && RefRelationship == Sema::Ref_Related)) && (InitCategory.isXValue() || - (InitCategory.isPRValue() && T2->isRecordType()) || - (InitCategory.isPRValue() && T2->isArrayType()))) { + (InitCategory.isPRValue() && + (S.getLangOpts().CPlusPlus1z || T2->isRecordType() || + T2->isArrayType())))) { ExprValueKind ValueKind = InitCategory.isXValue()? VK_XValue : VK_RValue; if (InitCategory.isPRValue() && T2->isRecordType()) { // The corresponding bullet in C++03 [dcl.init.ref]p5 gives the @@ -6604,7 +6640,26 @@ InitializationSequence::Perform(Sema &S, CreatedObject = Conversion->getReturnType()->isRecordType(); } + // C++14 and before: + // - if the function is a constructor, the call initializes a temporary + // of the cv-unqualified version of the destination type [...] + // C++1z: + // - if the function is a constructor, the call is a prvalue of the + // cv-unqualified version of the destination type whose return object + // is initialized by the constructor [...] + // Both: + // The [..] call is used to direct-initialize, according to the rules + // above, the object that is the destination of the + // copy-initialization. + // In C++14 and before, that always means the "constructors are + // considered" bullet, because we have arrived at a reference-related + // type. In C++1z, it only means that if the types are different or we + // didn't produce a prvalue, so just check for that case here. bool RequiresCopy = !IsCopy && !isReferenceBinding(Steps.back()); + if (S.getLangOpts().CPlusPlus1z && CurInit.get()->isRValue() && + S.Context.hasSameUnqualifiedType( + Entity.getType().getNonReferenceType(), CurInit.get()->getType())) + RequiresCopy = false; bool MaybeBindToTemp = RequiresCopy || shouldBindAsTemporary(Entity); if (!MaybeBindToTemp && CreatedObject && shouldDestroyTemporary(Entity)) { diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index aef23371e08..24c9ec6d507 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -4979,7 +4979,7 @@ TryObjectArgumentInitialization(Sema &S, SourceLocation Loc, QualType FromType, // cv-qualification on the member function declaration. // // However, when finding an implicit conversion sequence for the argument, we - // are not allowed to create temporaries or perform user-defined conversions + // are not allowed to perform user-defined conversions // (C++ [over.match.funcs]p5). We perform a simplified version of // reference binding here, that allows class rvalues to bind to // non-constant references. |