diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaExprCXX.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Sema/SemaExprCXX.cpp | 746 |
1 files changed, 423 insertions, 323 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm-project/clang/lib/Sema/SemaExprCXX.cpp index 9e2957fc8545..d885920b6c14 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaExprCXX.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaExprCXX.cpp @@ -156,196 +156,203 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, // } // // See also PR6358 and PR6359. - // For this reason, we're currently only doing the C++03 version of this - // code; the C++0x version has to wait until we get a proper spec. - QualType SearchType; - DeclContext *LookupCtx = nullptr; - bool isDependent = false; - bool LookInScope = false; + // + // For now, we accept all the cases in which the name given could plausibly + // be interpreted as a correct destructor name, issuing off-by-default + // extension diagnostics on the cases that don't strictly conform to the + // C++20 rules. This basically means we always consider looking in the + // nested-name-specifier prefix, the complete nested-name-specifier, and + // the scope, and accept if we find the expected type in any of the three + // places. if (SS.isInvalid()) return nullptr; + // Whether we've failed with a diagnostic already. + bool Failed = false; + + llvm::SmallVector<NamedDecl*, 8> FoundDecls; + llvm::SmallSet<CanonicalDeclPtr<Decl>, 8> FoundDeclSet; + // If we have an object type, it's because we are in a // pseudo-destructor-expression or a member access expression, and // we know what type we're looking for. - if (ObjectTypePtr) - SearchType = GetTypeFromParser(ObjectTypePtr); + QualType SearchType = + ObjectTypePtr ? GetTypeFromParser(ObjectTypePtr) : QualType(); - if (SS.isSet()) { - NestedNameSpecifier *NNS = SS.getScopeRep(); - - bool AlreadySearched = false; - bool LookAtPrefix = true; - // C++11 [basic.lookup.qual]p6: - // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier, - // the type-names are looked up as types in the scope designated by the - // nested-name-specifier. Similarly, in a qualified-id of the form: - // - // nested-name-specifier[opt] class-name :: ~ class-name - // - // the second class-name is looked up in the same scope as the first. - // - // Here, we determine whether the code below is permitted to look at the - // prefix of the nested-name-specifier. - DeclContext *DC = computeDeclContext(SS, EnteringContext); - if (DC && DC->isFileContext()) { - AlreadySearched = true; - LookupCtx = DC; - isDependent = false; - } else if (DC && isa<CXXRecordDecl>(DC)) { - LookAtPrefix = false; - LookInScope = true; - } - - // The second case from the C++03 rules quoted further above. - NestedNameSpecifier *Prefix = nullptr; - if (AlreadySearched) { - // Nothing left to do. - } else if (LookAtPrefix && (Prefix = NNS->getPrefix())) { - CXXScopeSpec PrefixSS; - PrefixSS.Adopt(NestedNameSpecifierLoc(Prefix, SS.location_data())); - LookupCtx = computeDeclContext(PrefixSS, EnteringContext); - isDependent = isDependentScopeSpecifier(PrefixSS); - } else if (ObjectTypePtr) { - LookupCtx = computeDeclContext(SearchType); - isDependent = SearchType->isDependentType(); - } else { - LookupCtx = computeDeclContext(SS, EnteringContext); - isDependent = LookupCtx && LookupCtx->isDependentContext(); - } - } else if (ObjectTypePtr) { - // C++ [basic.lookup.classref]p3: - // If the unqualified-id is ~type-name, the type-name is looked up - // in the context of the entire postfix-expression. If the type T - // of the object expression is of a class type C, the type-name is - // also looked up in the scope of class C. At least one of the - // lookups shall find a name that refers to (possibly - // cv-qualified) T. - LookupCtx = computeDeclContext(SearchType); - isDependent = SearchType->isDependentType(); - assert((isDependent || !SearchType->isIncompleteType()) && - "Caller should have completed object type"); - - LookInScope = true; - } else { - // Perform lookup into the current scope (only). - LookInScope = true; - } - - TypeDecl *NonMatchingTypeDecl = nullptr; - LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName); - for (unsigned Step = 0; Step != 2; ++Step) { - // Look for the name first in the computed lookup context (if we - // have one) and, if that fails to find a match, in the scope (if - // we're allowed to look there). - Found.clear(); - if (Step == 0 && LookupCtx) { - if (RequireCompleteDeclContext(SS, LookupCtx)) - return nullptr; - LookupQualifiedName(Found, LookupCtx); - } else if (Step == 1 && LookInScope && S) { - LookupName(Found, S); - } else { - continue; - } + auto CheckLookupResult = [&](LookupResult &Found) -> ParsedType { + auto IsAcceptableResult = [&](NamedDecl *D) -> bool { + auto *Type = dyn_cast<TypeDecl>(D->getUnderlyingDecl()); + if (!Type) + return false; - // FIXME: Should we be suppressing ambiguities here? - if (Found.isAmbiguous()) - return nullptr; + if (SearchType.isNull() || SearchType->isDependentType()) + return true; - if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) { QualType T = Context.getTypeDeclType(Type); - MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); + return Context.hasSameUnqualifiedType(T, SearchType); + }; - if (SearchType.isNull() || SearchType->isDependentType() || - Context.hasSameUnqualifiedType(T, SearchType)) { - // We found our type! + unsigned NumAcceptableResults = 0; + for (NamedDecl *D : Found) { + if (IsAcceptableResult(D)) + ++NumAcceptableResults; + + // Don't list a class twice in the lookup failure diagnostic if it's + // found by both its injected-class-name and by the name in the enclosing + // scope. + if (auto *RD = dyn_cast<CXXRecordDecl>(D)) + if (RD->isInjectedClassName()) + D = cast<NamedDecl>(RD->getParent()); + + if (FoundDeclSet.insert(D).second) + FoundDecls.push_back(D); + } + + // As an extension, attempt to "fix" an ambiguity by erasing all non-type + // results, and all non-matching results if we have a search type. It's not + // clear what the right behavior is if destructor lookup hits an ambiguity, + // but other compilers do generally accept at least some kinds of + // ambiguity. + if (Found.isAmbiguous() && NumAcceptableResults == 1) { + Diag(NameLoc, diag::ext_dtor_name_ambiguous); + LookupResult::Filter F = Found.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next(); + if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl())) + Diag(D->getLocation(), diag::note_destructor_type_here) + << Context.getTypeDeclType(TD); + else + Diag(D->getLocation(), diag::note_destructor_nontype_here); + if (!IsAcceptableResult(D)) + F.erase(); + } + F.done(); + } + + if (Found.isAmbiguous()) + Failed = true; + + if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) { + if (IsAcceptableResult(Type)) { + QualType T = Context.getTypeDeclType(Type); + MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); return CreateParsedType(T, Context.getTrivialTypeSourceInfo(T, NameLoc)); } + } - if (!SearchType.isNull()) - NonMatchingTypeDecl = Type; - } - - // If the name that we found is a class template name, and it is - // the same name as the template name in the last part of the - // nested-name-specifier (if present) or the object type, then - // this is the destructor for that class. - // FIXME: This is a workaround until we get real drafting for core - // issue 399, for which there isn't even an obvious direction. - if (ClassTemplateDecl *Template = Found.getAsSingle<ClassTemplateDecl>()) { - QualType MemberOfType; - if (SS.isSet()) { - if (DeclContext *Ctx = computeDeclContext(SS, EnteringContext)) { - // Figure out the type of the context, if it has one. - if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) - MemberOfType = Context.getTypeDeclType(Record); - } - } - if (MemberOfType.isNull()) - MemberOfType = SearchType; + return nullptr; + }; - if (MemberOfType.isNull()) - continue; + bool IsDependent = false; - // We're referring into a class template specialization. If the - // class template we found is the same as the template being - // specialized, we found what we are looking for. - if (const RecordType *Record = MemberOfType->getAs<RecordType>()) { - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) { - if (Spec->getSpecializedTemplate()->getCanonicalDecl() == - Template->getCanonicalDecl()) - return CreateParsedType( - MemberOfType, - Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); - } + auto LookupInObjectType = [&]() -> ParsedType { + if (Failed || SearchType.isNull()) + return nullptr; - continue; - } + IsDependent |= SearchType->isDependentType(); - // We're referring to an unresolved class template - // specialization. Determine whether we class template we found - // is the same as the template being specialized or, if we don't - // know which template is being specialized, that it at least - // has the same name. - if (const TemplateSpecializationType *SpecType - = MemberOfType->getAs<TemplateSpecializationType>()) { - TemplateName SpecName = SpecType->getTemplateName(); - - // The class template we found is the same template being - // specialized. - if (TemplateDecl *SpecTemplate = SpecName.getAsTemplateDecl()) { - if (SpecTemplate->getCanonicalDecl() == Template->getCanonicalDecl()) - return CreateParsedType( - MemberOfType, - Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); + LookupResult Found(*this, &II, NameLoc, LookupDestructorName); + DeclContext *LookupCtx = computeDeclContext(SearchType); + if (!LookupCtx) + return nullptr; + LookupQualifiedName(Found, LookupCtx); + return CheckLookupResult(Found); + }; - continue; - } + auto LookupInNestedNameSpec = [&](CXXScopeSpec &LookupSS) -> ParsedType { + if (Failed) + return nullptr; - // The class template we found has the same name as the - // (dependent) template name being specialized. - if (DependentTemplateName *DepTemplate - = SpecName.getAsDependentTemplateName()) { - if (DepTemplate->isIdentifier() && - DepTemplate->getIdentifier() == Template->getIdentifier()) - return CreateParsedType( - MemberOfType, - Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); + IsDependent |= isDependentScopeSpecifier(LookupSS); + DeclContext *LookupCtx = computeDeclContext(LookupSS, EnteringContext); + if (!LookupCtx) + return nullptr; - continue; - } - } + LookupResult Found(*this, &II, NameLoc, LookupDestructorName); + if (RequireCompleteDeclContext(LookupSS, LookupCtx)) { + Failed = true; + return nullptr; } + LookupQualifiedName(Found, LookupCtx); + return CheckLookupResult(Found); + }; + + auto LookupInScope = [&]() -> ParsedType { + if (Failed || !S) + return nullptr; + + LookupResult Found(*this, &II, NameLoc, LookupDestructorName); + LookupName(Found, S); + return CheckLookupResult(Found); + }; + + // C++2a [basic.lookup.qual]p6: + // In a qualified-id of the form + // + // nested-name-specifier[opt] type-name :: ~ type-name + // + // the second type-name is looked up in the same scope as the first. + // + // We interpret this as meaning that if you do a dual-scope lookup for the + // first name, you also do a dual-scope lookup for the second name, per + // C++ [basic.lookup.classref]p4: + // + // If the id-expression in a class member access is a qualified-id of the + // form + // + // class-name-or-namespace-name :: ... + // + // the class-name-or-namespace-name following the . or -> is first looked + // up in the class of the object expression and the name, if found, is used. + // Otherwise, it is looked up in the context of the entire + // postfix-expression. + // + // This looks in the same scopes as for an unqualified destructor name: + // + // C++ [basic.lookup.classref]p3: + // If the unqualified-id is ~ type-name, the type-name is looked up + // in the context of the entire postfix-expression. If the type T + // of the object expression is of a class type C, the type-name is + // also looked up in the scope of class C. At least one of the + // lookups shall find a name that refers to cv T. + // + // FIXME: The intent is unclear here. Should type-name::~type-name look in + // the scope anyway if it finds a non-matching name declared in the class? + // If both lookups succeed and find a dependent result, which result should + // we retain? (Same question for p->~type-name().) + + if (NestedNameSpecifier *Prefix = + SS.isSet() ? SS.getScopeRep()->getPrefix() : nullptr) { + // This is + // + // nested-name-specifier type-name :: ~ type-name + // + // Look for the second type-name in the nested-name-specifier. + CXXScopeSpec PrefixSS; + PrefixSS.Adopt(NestedNameSpecifierLoc(Prefix, SS.location_data())); + if (ParsedType T = LookupInNestedNameSpec(PrefixSS)) + return T; + } else { + // This is one of + // + // type-name :: ~ type-name + // ~ type-name + // + // Look in the scope and (if any) the object type. + if (ParsedType T = LookupInScope()) + return T; + if (ParsedType T = LookupInObjectType()) + return T; } - if (isDependent) { - // We didn't find our type, but that's okay: it's dependent - // anyway. + if (Failed) + return nullptr; + + if (IsDependent) { + // We didn't find our type, but that's OK: it's dependent anyway. // FIXME: What if we have no nested-name-specifier? QualType T = CheckTypenameType(ETK_None, SourceLocation(), @@ -354,26 +361,98 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, return ParsedType::make(T); } - if (NonMatchingTypeDecl) { - QualType T = Context.getTypeDeclType(NonMatchingTypeDecl); - Diag(NameLoc, diag::err_destructor_expr_type_mismatch) - << T << SearchType; - Diag(NonMatchingTypeDecl->getLocation(), diag::note_destructor_type_here) - << T; - } else if (ObjectTypePtr) - Diag(NameLoc, diag::err_ident_in_dtor_not_a_type) - << &II; - else { - SemaDiagnosticBuilder DtorDiag = Diag(NameLoc, - diag::err_destructor_class_name); - if (S) { - const DeclContext *Ctx = S->getEntity(); - if (const CXXRecordDecl *Class = dyn_cast_or_null<CXXRecordDecl>(Ctx)) - DtorDiag << FixItHint::CreateReplacement(SourceRange(NameLoc), - Class->getNameAsString()); + // The remaining cases are all non-standard extensions imitating the behavior + // of various other compilers. + unsigned NumNonExtensionDecls = FoundDecls.size(); + + if (SS.isSet()) { + // For compatibility with older broken C++ rules and existing code, + // + // nested-name-specifier :: ~ type-name + // + // also looks for type-name within the nested-name-specifier. + if (ParsedType T = LookupInNestedNameSpec(SS)) { + Diag(SS.getEndLoc(), diag::ext_dtor_named_in_wrong_scope) + << SS.getRange() + << FixItHint::CreateInsertion(SS.getEndLoc(), + ("::" + II.getName()).str()); + return T; + } + + // For compatibility with other compilers and older versions of Clang, + // + // nested-name-specifier type-name :: ~ type-name + // + // also looks for type-name in the scope. Unfortunately, we can't + // reasonably apply this fallback for dependent nested-name-specifiers. + if (SS.getScopeRep()->getPrefix()) { + if (ParsedType T = LookupInScope()) { + Diag(SS.getEndLoc(), diag::ext_qualified_dtor_named_in_lexical_scope) + << FixItHint::CreateRemoval(SS.getRange()); + Diag(FoundDecls.back()->getLocation(), diag::note_destructor_type_here) + << GetTypeFromParser(T); + return T; + } } } + // We didn't find anything matching; tell the user what we did find (if + // anything). + + // Don't tell the user about declarations we shouldn't have found. + FoundDecls.resize(NumNonExtensionDecls); + + // List types before non-types. + std::stable_sort(FoundDecls.begin(), FoundDecls.end(), + [](NamedDecl *A, NamedDecl *B) { + return isa<TypeDecl>(A->getUnderlyingDecl()) > + isa<TypeDecl>(B->getUnderlyingDecl()); + }); + + // Suggest a fixit to properly name the destroyed type. + auto MakeFixItHint = [&]{ + const CXXRecordDecl *Destroyed = nullptr; + // FIXME: If we have a scope specifier, suggest its last component? + if (!SearchType.isNull()) + Destroyed = SearchType->getAsCXXRecordDecl(); + else if (S) + Destroyed = dyn_cast_or_null<CXXRecordDecl>(S->getEntity()); + if (Destroyed) + return FixItHint::CreateReplacement(SourceRange(NameLoc), + Destroyed->getNameAsString()); + return FixItHint(); + }; + + if (FoundDecls.empty()) { + // FIXME: Attempt typo-correction? + Diag(NameLoc, diag::err_undeclared_destructor_name) + << &II << MakeFixItHint(); + } else if (!SearchType.isNull() && FoundDecls.size() == 1) { + if (auto *TD = dyn_cast<TypeDecl>(FoundDecls[0]->getUnderlyingDecl())) { + assert(!SearchType.isNull() && + "should only reject a type result if we have a search type"); + QualType T = Context.getTypeDeclType(TD); + Diag(NameLoc, diag::err_destructor_expr_type_mismatch) + << T << SearchType << MakeFixItHint(); + } else { + Diag(NameLoc, diag::err_destructor_expr_nontype) + << &II << MakeFixItHint(); + } + } else { + Diag(NameLoc, SearchType.isNull() ? diag::err_destructor_name_nontype + : diag::err_destructor_expr_mismatch) + << &II << SearchType << MakeFixItHint(); + } + + for (NamedDecl *FoundD : FoundDecls) { + if (auto *TD = dyn_cast<TypeDecl>(FoundD->getUnderlyingDecl())) + Diag(FoundD->getLocation(), diag::note_destructor_type_here) + << Context.getTypeDeclType(TD); + else + Diag(FoundD->getLocation(), diag::note_destructor_nontype_here) + << FoundD; + } + return nullptr; } @@ -625,11 +704,11 @@ getUuidAttrOfType(Sema &SemaRef, QualType QT, } /// Build a Microsoft __uuidof expression with a type operand. -ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, +ExprResult Sema::BuildCXXUuidof(QualType Type, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc) { - StringRef UuidStr; + MSGuidDecl *Guid = nullptr; if (!Operand->getType()->isDependentType()) { llvm::SmallSetVector<const UuidAttr *, 1> UuidAttrs; getUuidAttrOfType(*this, Operand->getType(), UuidAttrs); @@ -637,22 +716,21 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); if (UuidAttrs.size() > 1) return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); - UuidStr = UuidAttrs.back()->getGuid(); + Guid = UuidAttrs.back()->getGuidDecl(); } - return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), Operand, UuidStr, - SourceRange(TypeidLoc, RParenLoc)); + return new (Context) + CXXUuidofExpr(Type, Operand, Guid, SourceRange(TypeidLoc, RParenLoc)); } /// Build a Microsoft __uuidof expression with an expression operand. -ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, - SourceLocation TypeidLoc, - Expr *E, - SourceLocation RParenLoc) { - StringRef UuidStr; +ExprResult Sema::BuildCXXUuidof(QualType Type, SourceLocation TypeidLoc, + Expr *E, SourceLocation RParenLoc) { + MSGuidDecl *Guid = nullptr; if (!E->getType()->isDependentType()) { if (E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - UuidStr = "00000000-0000-0000-0000-000000000000"; + // A null pointer results in {00000000-0000-0000-0000-000000000000}. + Guid = Context.getMSGuidDecl(MSGuidDecl::Parts{}); } else { llvm::SmallSetVector<const UuidAttr *, 1> UuidAttrs; getUuidAttrOfType(*this, E->getType(), UuidAttrs); @@ -660,29 +738,20 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); if (UuidAttrs.size() > 1) return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); - UuidStr = UuidAttrs.back()->getGuid(); + Guid = UuidAttrs.back()->getGuidDecl(); } } - return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), E, UuidStr, - SourceRange(TypeidLoc, RParenLoc)); + return new (Context) + CXXUuidofExpr(Type, E, Guid, SourceRange(TypeidLoc, RParenLoc)); } /// ActOnCXXUuidof - Parse __uuidof( type-id ) or __uuidof (expression); ExprResult Sema::ActOnCXXUuidof(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc) { - // If MSVCGuidDecl has not been cached, do the lookup. - if (!MSVCGuidDecl) { - IdentifierInfo *GuidII = &PP.getIdentifierTable().get("_GUID"); - LookupResult R(*this, GuidII, SourceLocation(), LookupTagName); - LookupQualifiedName(R, Context.getTranslationUnitDecl()); - MSVCGuidDecl = R.getAsSingle<RecordDecl>(); - if (!MSVCGuidDecl) - return ExprError(Diag(OpLoc, diag::err_need_header_before_ms_uuidof)); - } - - QualType GuidType = Context.getTypeDeclType(MSVCGuidDecl); + QualType GuidType = Context.getMSGuidType(); + GuidType.addConst(); if (isType) { // The operand is a type; handle it as such. @@ -877,6 +946,11 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, E->getSourceRange())) return true; + if (!isPointer && Ty->isSizelessType()) { + Diag(ThrowLoc, diag::err_throw_sizeless) << Ty << E->getSourceRange(); + return true; + } + if (RequireNonAbstractType(ThrowLoc, ExceptionObjectTy, diag::err_throw_abstract_type, E)) return true; @@ -1743,8 +1817,9 @@ Sema::isUnavailableAlignedAllocationFunction(const FunctionDecl &FD) const { return false; if (FD.isDefined()) return false; - bool IsAligned = false; - if (FD.isReplaceableGlobalAllocationFunction(&IsAligned) && IsAligned) + Optional<unsigned> AlignmentParam; + if (FD.isReplaceableGlobalAllocationFunction(&AlignmentParam) && + AlignmentParam.hasValue()) return true; return false; } @@ -2062,8 +2137,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, SmallVector<Expr *, 8> AllPlaceArgs; if (OperatorNew) { - const FunctionProtoType *Proto = - OperatorNew->getType()->getAs<FunctionProtoType>(); + auto *Proto = OperatorNew->getType()->castAs<FunctionProtoType>(); VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; @@ -2071,18 +2145,80 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // arguments. Skip the first parameter because we don't have a corresponding // argument. Skip the second parameter too if we're passing in the // alignment; we've already filled it in. + unsigned NumImplicitArgs = PassAlignment ? 2 : 1; if (GatherArgumentsForCall(PlacementLParen, OperatorNew, Proto, - PassAlignment ? 2 : 1, PlacementArgs, - AllPlaceArgs, CallType)) + NumImplicitArgs, PlacementArgs, AllPlaceArgs, + CallType)) return ExprError(); if (!AllPlaceArgs.empty()) PlacementArgs = AllPlaceArgs; - // FIXME: This is wrong: PlacementArgs misses out the first (size) argument. - DiagnoseSentinelCalls(OperatorNew, PlacementLParen, PlacementArgs); - - // FIXME: Missing call to CheckFunctionCall or equivalent + // We would like to perform some checking on the given `operator new` call, + // but the PlacementArgs does not contain the implicit arguments, + // namely allocation size and maybe allocation alignment, + // so we need to conjure them. + + QualType SizeTy = Context.getSizeType(); + unsigned SizeTyWidth = Context.getTypeSize(SizeTy); + + llvm::APInt SingleEltSize( + SizeTyWidth, Context.getTypeSizeInChars(AllocType).getQuantity()); + + // How many bytes do we want to allocate here? + llvm::Optional<llvm::APInt> AllocationSize; + if (!ArraySize.hasValue() && !AllocType->isDependentType()) { + // For non-array operator new, we only want to allocate one element. + AllocationSize = SingleEltSize; + } else if (KnownArraySize.hasValue() && !AllocType->isDependentType()) { + // For array operator new, only deal with static array size case. + bool Overflow; + AllocationSize = llvm::APInt(SizeTyWidth, *KnownArraySize) + .umul_ov(SingleEltSize, Overflow); + (void)Overflow; + assert( + !Overflow && + "Expected that all the overflows would have been handled already."); + } + + IntegerLiteral AllocationSizeLiteral( + Context, + AllocationSize.getValueOr(llvm::APInt::getNullValue(SizeTyWidth)), + SizeTy, SourceLocation()); + // Otherwise, if we failed to constant-fold the allocation size, we'll + // just give up and pass-in something opaque, that isn't a null pointer. + OpaqueValueExpr OpaqueAllocationSize(SourceLocation(), SizeTy, VK_RValue, + OK_Ordinary, /*SourceExpr=*/nullptr); + + // Let's synthesize the alignment argument in case we will need it. + // Since we *really* want to allocate these on stack, this is slightly ugly + // because there might not be a `std::align_val_t` type. + EnumDecl *StdAlignValT = getStdAlignValT(); + QualType AlignValT = + StdAlignValT ? Context.getTypeDeclType(StdAlignValT) : SizeTy; + IntegerLiteral AlignmentLiteral( + Context, + llvm::APInt(Context.getTypeSize(SizeTy), + Alignment / Context.getCharWidth()), + SizeTy, SourceLocation()); + ImplicitCastExpr DesiredAlignment(ImplicitCastExpr::OnStack, AlignValT, + CK_IntegralCast, &AlignmentLiteral, + VK_RValue); + + // Adjust placement args by prepending conjured size and alignment exprs. + llvm::SmallVector<Expr *, 8> CallArgs; + CallArgs.reserve(NumImplicitArgs + PlacementArgs.size()); + CallArgs.emplace_back(AllocationSize.hasValue() + ? static_cast<Expr *>(&AllocationSizeLiteral) + : &OpaqueAllocationSize); + if (PassAlignment) + CallArgs.emplace_back(&DesiredAlignment); + CallArgs.insert(CallArgs.end(), PlacementArgs.begin(), PlacementArgs.end()); + + DiagnoseSentinelCalls(OperatorNew, PlacementLParen, CallArgs); + + checkCall(OperatorNew, Proto, /*ThisArg=*/nullptr, CallArgs, + /*IsMemberFunction=*/false, StartLoc, Range, CallType); // Warn if the type is over-aligned and is being allocated by (unaligned) // global operator new. @@ -2194,7 +2330,8 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, return Diag(Loc, diag::err_bad_new_type) << AllocType << 1 << R; else if (!AllocType->isDependentType() && - RequireCompleteType(Loc, AllocType, diag::err_new_incomplete_type,R)) + RequireCompleteSizedType( + Loc, AllocType, diag::err_new_incomplete_or_sizeless_type, R)) return true; else if (RequireNonAbstractType(Loc, AllocType, diag::err_allocation_of_abstract_type)) @@ -2516,8 +2653,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // for template argument deduction and for comparison purposes. QualType ExpectedFunctionType; { - const FunctionProtoType *Proto - = OperatorNew->getType()->getAs<FunctionProtoType>(); + auto *Proto = OperatorNew->getType()->castAs<FunctionProtoType>(); SmallVector<QualType, 4> ArgTypes; ArgTypes.push_back(Context.VoidPtrTy); @@ -2836,6 +2972,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, Alloc->setParams(ParamDecls); if (ExtraAttr) Alloc->addAttr(ExtraAttr); + AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(Alloc); Context.getTranslationUnitDecl()->addDecl(Alloc); IdResolver.tryAddTopLevelDecl(Alloc, Name); }; @@ -3320,7 +3457,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // this, so we treat it as a warning unless we're in a SFINAE context. Diag(StartLoc, diag::ext_delete_void_ptr_operand) << Type << Ex.get()->getSourceRange(); - } else if (Pointee->isFunctionType() || Pointee->isVoidType()) { + } else if (Pointee->isFunctionType() || Pointee->isVoidType() || + Pointee->isSizelessType()) { return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex.get()->getSourceRange()); } else if (!Pointee->isDependentType()) { @@ -3866,15 +4004,17 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, ICS.DiagnoseAmbiguousConversion(*this, From->getExprLoc(), PDiag(diag::err_typecheck_ambiguous_condition) << From->getSourceRange()); - return ExprError(); + return ExprError(); case ImplicitConversionSequence::EllipsisConversion: llvm_unreachable("Cannot perform an ellipsis conversion"); case ImplicitConversionSequence::BadConversion: - bool Diagnosed = - DiagnoseAssignmentResult(Incompatible, From->getExprLoc(), ToType, - From->getType(), From, Action); + Sema::AssignConvertType ConvTy = + CheckAssignmentConstraints(From->getExprLoc(), ToType, From->getType()); + bool Diagnosed = DiagnoseAssignmentResult( + ConvTy == Compatible ? Incompatible : ConvTy, From->getExprLoc(), + ToType, From->getType(), From, Action); assert(Diagnosed && "failed to diagnose bad conversion"); (void)Diagnosed; return ExprError(); } @@ -4214,9 +4354,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // Case 2. _Complex x -> y } else { - const ComplexType *FromComplex = From->getType()->getAs<ComplexType>(); - assert(FromComplex); - + auto *FromComplex = From->getType()->castAs<ComplexType>(); QualType ElType = FromComplex->getElementType(); bool isFloatingComplex = ElType->isRealFloatingType(); @@ -4345,6 +4483,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, VK_RValue, nullptr, CCK).get(); } + // Materialize a temporary if we're implicitly converting to a reference + // type. This is not required by the C++ rules but is necessary to maintain + // AST invariants. + if (ToType->isReferenceType() && From->isRValue()) { + ExprResult Res = TemporaryMaterializationConversion(From); + if (Res.isInvalid()) + return ExprError(); + From = Res.get(); + } + // If this conversion sequence succeeded and involved implicitly converting a // _Nullable type to a _Nonnull one, complain. if (!isCast(CCK)) @@ -4501,8 +4649,7 @@ static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op, CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op); if((Operator->*IsDesiredOp)()) { FoundOperator = true; - const FunctionProtoType *CPT = - Operator->getType()->getAs<FunctionProtoType>(); + auto *CPT = Operator->getType()->castAs<FunctionProtoType>(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT || !CPT->isNothrow()) return false; @@ -4531,7 +4678,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, case UTT_IsArray: return T->isArrayType(); case UTT_IsPointer: - return T->isPointerType(); + return T->isAnyPointerType(); case UTT_IsLvalueReference: return T->isLValueReferenceType(); case UTT_IsRvalueReference: @@ -4751,8 +4898,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, if (C.getLangOpts().AccessControl && Destructor->getAccess() != AS_public) return false; if (UTT == UTT_IsNothrowDestructible) { - const FunctionProtoType *CPT = - Destructor->getType()->getAs<FunctionProtoType>(); + auto *CPT = Destructor->getType()->castAs<FunctionProtoType>(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT || !CPT->isNothrow()) return false; @@ -4840,8 +4986,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, auto *Constructor = cast<CXXConstructorDecl>(ND->getUnderlyingDecl()); if (Constructor->isCopyConstructor(FoundTQs)) { FoundConstructor = true; - const FunctionProtoType *CPT - = Constructor->getType()->getAs<FunctionProtoType>(); + auto *CPT = Constructor->getType()->castAs<FunctionProtoType>(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT) return false; @@ -4879,8 +5024,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, auto *Constructor = cast<CXXConstructorDecl>(ND->getUnderlyingDecl()); if (Constructor->isDefaultConstructor()) { FoundConstructor = true; - const FunctionProtoType *CPT - = Constructor->getType()->getAs<FunctionProtoType>(); + auto *CPT = Constructor->getType()->castAs<FunctionProtoType>(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT) return false; @@ -4973,20 +5117,19 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, if (RD && RD->isAbstract()) return false; - SmallVector<OpaqueValueExpr, 2> OpaqueArgExprs; + llvm::BumpPtrAllocator OpaqueExprAllocator; SmallVector<Expr *, 2> ArgExprs; ArgExprs.reserve(Args.size() - 1); for (unsigned I = 1, N = Args.size(); I != N; ++I) { QualType ArgTy = Args[I]->getType(); if (ArgTy->isObjectType() || ArgTy->isFunctionType()) ArgTy = S.Context.getRValueReferenceType(ArgTy); - OpaqueArgExprs.push_back( - OpaqueValueExpr(Args[I]->getTypeLoc().getBeginLoc(), - ArgTy.getNonLValueExprType(S.Context), - Expr::getValueKindForType(ArgTy))); + ArgExprs.push_back( + new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>()) + OpaqueValueExpr(Args[I]->getTypeLoc().getBeginLoc(), + ArgTy.getNonLValueExprType(S.Context), + Expr::getValueKindForType(ArgTy))); } - for (Expr &E : OpaqueArgExprs) - ArgExprs.push_back(&E); // Perform the initialization in an unevaluated context within a SFINAE // trap at translation unit scope. @@ -5536,7 +5679,7 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS, // C++2a allows functions with ref-qualifier & if their cv-qualifier-seq // is (exactly) 'const'. if (Proto->isConst() && !Proto->isVolatile()) - Diag(Loc, getLangOpts().CPlusPlus2a + Diag(Loc, getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue : diag::ext_pointer_to_const_ref_member_on_rvalue); else @@ -5765,7 +5908,7 @@ QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, RHS = DefaultFunctionArrayLvalueConversion(RHS.get()); QualType CondType = Cond.get()->getType(); - const auto *CondVT = CondType->getAs<VectorType>(); + const auto *CondVT = CondType->castAs<VectorType>(); QualType CondElementTy = CondVT->getElementType(); unsigned CondElementCount = CondVT->getNumElements(); QualType LHSType = LHS.get()->getType(); @@ -5821,7 +5964,7 @@ QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, return {}; } ResultType = Context.getVectorType( - ResultElementTy, CondType->getAs<VectorType>()->getNumElements(), + ResultElementTy, CondType->castAs<VectorType>()->getNumElements(), VectorType::GenericVector); LHS = ImpCastExprToType(LHS.get(), ResultType, CK_VectorSplat); @@ -5830,9 +5973,9 @@ QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, assert(!ResultType.isNull() && ResultType->isVectorType() && "Result should have been a vector type"); - QualType ResultElementTy = ResultType->getAs<VectorType>()->getElementType(); - unsigned ResultElementCount = - ResultType->getAs<VectorType>()->getNumElements(); + auto *ResultVectorTy = ResultType->castAs<VectorType>(); + QualType ResultElementTy = ResultVectorTy->getElementType(); + unsigned ResultElementCount = ResultVectorTy->getNumElements(); if (ResultElementCount != CondElementCount) { Diag(QuestionLoc, diag::err_conditional_vector_size) << CondType @@ -6629,8 +6772,7 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { else if (const MemberPointerType *MemPtr = T->getAs<MemberPointerType>()) T = MemPtr->getPointeeType(); - const FunctionType *FTy = T->getAs<FunctionType>(); - assert(FTy && "call to value not of function type?"); + auto *FTy = T->castAs<FunctionType>(); ReturnsRetained = FTy->getExtInfo().getProducesResult(); // ActOnStmtExpr arranges things so that StmtExprs of retainable @@ -6694,6 +6836,9 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { VK_RValue); } + if (E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct) + Cleanup.setExprNeedsCleanups(true); + if (!getLangOpts().CPlusPlus) return E; @@ -6841,9 +6986,10 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) { return ExprError(); if (RHS.get() == BO->getRHS()) return E; - return new (Context) BinaryOperator( - BO->getLHS(), RHS.get(), BO_Comma, BO->getType(), BO->getValueKind(), - BO->getObjectKind(), BO->getOperatorLoc(), BO->getFPFeatures()); + return BinaryOperator::Create(Context, BO->getLHS(), RHS.get(), BO_Comma, + BO->getType(), BO->getValueKind(), + BO->getObjectKind(), BO->getOperatorLoc(), + BO->getFPFeatures(getLangOpts())); } } @@ -7445,13 +7591,13 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, // a difference in ARC, but outside of ARC the resulting block literal // follows the normal lifetime rules for block literals instead of being // autoreleased. - DiagnosticErrorTrap Trap(Diags); PushExpressionEvaluationContext( ExpressionEvaluationContext::PotentiallyEvaluated); ExprResult BlockExp = BuildBlockForLambdaConversion( Exp.get()->getExprLoc(), Exp.get()->getExprLoc(), Method, Exp.get()); PopExpressionEvaluationContext(); + // FIXME: This note should be produced by a CodeSynthesisContext. if (BlockExp.isInvalid()) Diag(Exp.get()->getExprLoc(), diag::note_lambda_to_block_conv); return BlockExp; @@ -7510,61 +7656,6 @@ ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation, return BuildCXXNoexceptExpr(KeyLoc, Operand, RParen); } -static bool IsSpecialDiscardedValue(Expr *E) { - // In C++11, discarded-value expressions of a certain form are special, - // according to [expr]p10: - // The lvalue-to-rvalue conversion (4.1) is applied only if the - // expression is an lvalue of volatile-qualified type and it has - // one of the following forms: - E = E->IgnoreParens(); - - // - id-expression (5.1.1), - if (isa<DeclRefExpr>(E)) - return true; - - // - subscripting (5.2.1), - if (isa<ArraySubscriptExpr>(E)) - return true; - - // - class member access (5.2.5), - if (isa<MemberExpr>(E)) - return true; - - // - indirection (5.3.1), - if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) - if (UO->getOpcode() == UO_Deref) - return true; - - if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { - // - pointer-to-member operation (5.5), - if (BO->isPtrMemOp()) - return true; - - // - comma expression (5.18) where the right operand is one of the above. - if (BO->getOpcode() == BO_Comma) - return IsSpecialDiscardedValue(BO->getRHS()); - } - - // - conditional expression (5.16) where both the second and the third - // operands are one of the above, or - if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) - return IsSpecialDiscardedValue(CO->getTrueExpr()) && - IsSpecialDiscardedValue(CO->getFalseExpr()); - // The related edge case of "*x ?: *x". - if (BinaryConditionalOperator *BCO = - dyn_cast<BinaryConditionalOperator>(E)) { - if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(BCO->getTrueExpr())) - return IsSpecialDiscardedValue(OVE->getSourceExpr()) && - IsSpecialDiscardedValue(BCO->getFalseExpr()); - } - - // Objective-C++ extensions to the rule. - if (isa<PseudoObjectExpr>(E) || isa<ObjCIvarRefExpr>(E)) - return true; - - return false; -} - /// Perform the conversions required for an expression used in a /// context that ignores the result. ExprResult Sema::IgnoredValueConversions(Expr *E) { @@ -7589,23 +7680,20 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) { return E; } - if (getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus) { // The C++11 standard defines the notion of a discarded-value expression; // normally, we don't need to do anything to handle it, but if it is a // volatile lvalue with a special form, we perform an lvalue-to-rvalue // conversion. - if (getLangOpts().CPlusPlus11 && E->isGLValue() && - E->getType().isVolatileQualified()) { - if (IsSpecialDiscardedValue(E)) { - ExprResult Res = DefaultLvalueConversion(E); - if (Res.isInvalid()) - return E; - E = Res.get(); - } else { - // Per C++2a [expr.ass]p5, a volatile assignment is not deprecated if - // it occurs as a discarded-value expression. - CheckUnusedVolatileAssignment(E); - } + if (getLangOpts().CPlusPlus11 && E->isReadIfDiscardedInCPlusPlus11()) { + ExprResult Res = DefaultLvalueConversion(E); + if (Res.isInvalid()) + return E; + E = Res.get(); + } else { + // Per C++2a [expr.ass]p5, a volatile assignment is not deprecated if + // it occurs as a discarded-value expression. + CheckUnusedVolatileAssignment(E); } // C++1z: @@ -8161,6 +8249,7 @@ public: ExprResult Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl, + bool RecoverUncorrectedTypos, llvm::function_ref<ExprResult(Expr *)> Filter) { // If the current evaluation context indicates there are uncorrected typos // and the current expression isn't guaranteed to not have typos, try to @@ -8173,6 +8262,16 @@ Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl, TyposResolved -= DelayedTypos.size(); if (Result.isInvalid() || Result.get() != E) { ExprEvalContexts.back().NumTypos -= TyposResolved; + if (Result.isInvalid() && RecoverUncorrectedTypos) { + struct TyposReplace : TreeTransform<TyposReplace> { + TyposReplace(Sema &SemaRef) : TreeTransform(SemaRef) {} + ExprResult TransformTypoExpr(clang::TypoExpr *E) { + return this->SemaRef.CreateRecoveryExpr(E->getBeginLoc(), + E->getEndLoc(), {}); + } + } TT(*this); + return TT.TransformExpr(E); + } return Result; } assert(TyposResolved == 0 && "Corrected typo but got same Expr back?"); @@ -8211,7 +8310,8 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, DiagnoseUnusedExprResult(FullExpr.get()); } - FullExpr = CorrectDelayedTyposInExpr(FullExpr.get()); + FullExpr = CorrectDelayedTyposInExpr(FullExpr.get(), /*InitDecl=*/nullptr, + /*RecoverUncorrectedTypos=*/true); if (FullExpr.isInvalid()) return ExprError(); |