aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Sema/SemaExprCXX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaExprCXX.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Sema/SemaExprCXX.cpp746
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();