diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-12-15 02:28:18 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-12-15 02:28:18 +0000 |
commit | 81f5ade22790685efa5542bd8b7e7fb2c6b6c56c (patch) | |
tree | 23c92251419f2a497e8abcd378c2fa5b8b7849b6 /clang/lib | |
parent | 1a328f508f99473907bbca0e5a40e9f57209a5da (diff) | |
download | bcm5719-llvm-81f5ade22790685efa5542bd8b7e7fb2c6b6c56c.tar.gz bcm5719-llvm-81f5ade22790685efa5542bd8b7e7fb2c6b6c56c.zip |
Move checks for creation of objects of abstract class type from the various
constructs that can do so into the initialization code. This fixes a number
of different cases in which we used to fail to check for abstract types.
Thanks to Tim Shen for inspiring the weird code that uncovered this!
llvm-svn: 289753
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 30 | ||||
-rw-r--r-- | clang/lib/Sema/SemaObjCProperty.cpp | 6 |
3 files changed, 33 insertions, 10 deletions
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index a4546cec5ab..74beeac7244 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1291,10 +1291,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, diag::err_invalid_incomplete_type_use, FullRange)) return ExprError(); - if (RequireNonAbstractType(TyBeginLoc, Ty, - diag::err_allocation_of_abstract_type)) - return ExprError(); - InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); InitializationKind Kind = Exprs.size() ? ListInitialization @@ -5491,9 +5487,6 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) { if (LTy->isRecordType()) { // The operands have class type. Make a temporary copy. - if (RequireNonAbstractType(QuestionLoc, LTy, - diag::err_allocation_of_abstract_type)) - return QualType(); InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); ExprResult LHSCopy = PerformCopyInitialization(Entity, diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 6ece7c8d784..ce012896f5b 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -4599,7 +4599,7 @@ static void TryValueInitialization(Sema &S, MultiExprArg Args(&InitListAsExpr, InitList ? 1 : 0); bool InitListSyntax = InitList; - // FIXME: Instead of creating a CXXConstructExpr of non-array type here, + // FIXME: Instead of creating a CXXConstructExpr of array type here, // wrap a class-typed CXXConstructExpr in an ArrayInitLoopExpr. return TryConstructorInitialization( S, Entity, Kind, Args, T, Entity.getType(), Sequence, InitListSyntax); @@ -6366,6 +6366,8 @@ ExprResult Sema::TemporaryMaterializationConversion(Expr *E) { return E; // C++1z [conv.rval]/1: T shall be a complete type. + // FIXME: Does this ever matter (can we form a prvalue of incomplete type)? + // If so, we should check for a non-abstract class type here too. QualType T = E->getType(); if (RequireCompleteType(E->getExprLoc(), T, diag::err_incomplete_type)) return ExprError(); @@ -6541,6 +6543,17 @@ InitializationSequence::Perform(Sema &S, break; } + // C++ [class.abstract]p2: + // no objects of an abstract class can be created except as subobjects + // of a class derived from it + auto checkAbstractType = [&](QualType T) -> bool { + if (Entity.getKind() == InitializedEntity::EK_Base || + Entity.getKind() == InitializedEntity::EK_Delegating) + return false; + return S.RequireNonAbstractType(Kind.getLocation(), T, + diag::err_allocation_of_abstract_type); + }; + // Walk through the computed steps for the initialization sequence, // performing the specified conversions along the way. bool ConstructorInitRequiresZeroInit = false; @@ -6647,6 +6660,9 @@ InitializationSequence::Perform(Sema &S, } case SK_FinalCopy: + if (checkAbstractType(Step->Type)) + return ExprError(); + // If the overall initialization is initializing a temporary, we already // bound our argument if it was necessary to do so. If not (if we're // ultimately initializing a non-temporary), our argument needs to be @@ -6731,6 +6747,9 @@ InitializationSequence::Perform(Sema &S, CreatedObject = Conversion->getReturnType()->isRecordType(); } + if (CreatedObject && checkAbstractType(CurInit.get()->getType())) + return ExprError(); + CurInit = ImplicitCastExpr::Create(S.Context, CurInit.get()->getType(), CastKind, CurInit.get(), nullptr, CurInit.get()->getValueKind()); @@ -6813,6 +6832,9 @@ InitializationSequence::Perform(Sema &S, } case SK_ListInitialization: { + if (checkAbstractType(Step->Type)) + return ExprError(); + InitListExpr *InitList = cast<InitListExpr>(CurInit.get()); // If we're not initializing the top-level entity, we need to create an // InitializeTemporary entity for our target type. @@ -6849,6 +6871,9 @@ InitializationSequence::Perform(Sema &S, } case SK_ConstructorInitializationFromList: { + if (checkAbstractType(Step->Type)) + return ExprError(); + // When an initializer list is passed for a parameter of type "reference // to object", we don't get an EK_Temporary entity, but instead an // EK_Parameter entity with reference type. @@ -6892,6 +6917,9 @@ InitializationSequence::Perform(Sema &S, case SK_ConstructorInitialization: case SK_StdInitializerListConstructorCall: { + if (checkAbstractType(Step->Type)) + return ExprError(); + // When an initializer list is passed for a parameter of type "reference // to object", we don't get an EK_Temporary entity, but instead an // EK_Parameter entity with reference type. diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 9ab80b4f79d..3481b82679c 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -1146,9 +1146,11 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, diag::err_abstract_type_in_decl, AbstractSynthesizedIvarType)) { Diag(property->getLocation(), diag::note_property_declare); + // An abstract type is as bad as an incomplete type. + CompleteTypeErr = true; + } + if (CompleteTypeErr) Ivar->setInvalidDecl(); - } else if (CompleteTypeErr) - Ivar->setInvalidDecl(); ClassImpDecl->addDecl(Ivar); IDecl->makeDeclVisibleInContext(Ivar); |