diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 64 | ||||
-rw-r--r-- | clang/lib/AST/ItaniumMangle.cpp | 3 | ||||
-rw-r--r-- | clang/lib/AST/TypePrinter.cpp | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGCall.cpp | 9 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 19 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 17 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclObjC.cpp | 8 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 25 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 5 |
9 files changed, 132 insertions, 20 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 4d26748b077..82e74528d19 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -7968,9 +7968,17 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (lproto->getTypeQuals() != rproto->getTypeQuals()) return QualType(); - if (!doFunctionTypesMatchOnExtParameterInfos(rproto, lproto)) + SmallVector<FunctionProtoType::ExtParameterInfo, 4> newParamInfos; + bool canUseLeft, canUseRight; + if (!mergeExtParameterInfo(lproto, rproto, canUseLeft, canUseRight, + newParamInfos)) return QualType(); + if (!canUseLeft) + allLTypes = false; + if (!canUseRight) + allRTypes = false; + // Check parameter type compatibility SmallVector<QualType, 10> types; for (unsigned i = 0, n = lproto->getNumParams(); i < n; i++) { @@ -8001,6 +8009,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, FunctionProtoType::ExtProtoInfo EPI = lproto->getExtProtoInfo(); EPI.ExtInfo = einfo; + EPI.ExtParameterInfos = + newParamInfos.empty() ? nullptr : newParamInfos.data(); return getFunctionType(retType, types, EPI); } @@ -8360,26 +8370,50 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, llvm_unreachable("Invalid Type::Class!"); } -bool ASTContext::doFunctionTypesMatchOnExtParameterInfos( - const FunctionProtoType *firstFnType, - const FunctionProtoType *secondFnType) { +bool ASTContext::mergeExtParameterInfo( + const FunctionProtoType *FirstFnType, const FunctionProtoType *SecondFnType, + bool &CanUseFirst, bool &CanUseSecond, + SmallVectorImpl<FunctionProtoType::ExtParameterInfo> &NewParamInfos) { + assert(NewParamInfos.empty() && "param info list not empty"); + CanUseFirst = CanUseSecond = true; + bool FirstHasInfo = FirstFnType->hasExtParameterInfos(); + bool SecondHasInfo = SecondFnType->hasExtParameterInfos(); + // Fast path: if the first type doesn't have ext parameter infos, - // we match if and only if they second type also doesn't have them. - if (!firstFnType->hasExtParameterInfos()) - return !secondFnType->hasExtParameterInfos(); + // we match if and only if the second type also doesn't have them. + if (!FirstHasInfo && !SecondHasInfo) + return true; - // Otherwise, we can only match if the second type has them. - if (!secondFnType->hasExtParameterInfos()) - return false; + bool NeedParamInfo = false; + size_t E = FirstHasInfo ? FirstFnType->getExtParameterInfos().size() + : SecondFnType->getExtParameterInfos().size(); - auto firstEPI = firstFnType->getExtParameterInfos(); - auto secondEPI = secondFnType->getExtParameterInfos(); - assert(firstEPI.size() == secondEPI.size()); + for (size_t I = 0; I < E; ++I) { + FunctionProtoType::ExtParameterInfo FirstParam, SecondParam; + if (FirstHasInfo) + FirstParam = FirstFnType->getExtParameterInfo(I); + if (SecondHasInfo) + SecondParam = SecondFnType->getExtParameterInfo(I); - for (size_t i = 0, n = firstEPI.size(); i != n; ++i) { - if (firstEPI[i] != secondEPI[i]) + // Cannot merge unless everything except the noescape flag matches. + if (FirstParam.withIsNoEscape(false) != SecondParam.withIsNoEscape(false)) return false; + + bool FirstNoEscape = FirstParam.isNoEscape(); + bool SecondNoEscape = SecondParam.isNoEscape(); + bool IsNoEscape = FirstNoEscape && SecondNoEscape; + NewParamInfos.push_back(FirstParam.withIsNoEscape(IsNoEscape)); + if (NewParamInfos.back().getOpaqueValue()) + NeedParamInfo = true; + if (FirstNoEscape != IsNoEscape) + CanUseFirst = false; + if (SecondNoEscape != IsNoEscape) + CanUseSecond = false; } + + if (!NeedParamInfo) + NewParamInfos.clear(); + return true; } diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index dbda7a5dbd4..a9c5ab2cc1d 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2643,6 +2643,9 @@ CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) { if (PI.isConsumed()) mangleVendorQualifier("ns_consumed"); + + if (PI.isNoEscape()) + mangleVendorQualifier("noescape"); } // <type> ::= <function-type> diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 15c63bf4ed9..1f5b4834896 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -665,6 +665,8 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, auto EPI = T->getExtParameterInfo(i); if (EPI.isConsumed()) OS << "__attribute__((ns_consumed)) "; + if (EPI.isNoEscape()) + OS << "__attribute__((noescape)) "; auto ABI = EPI.getABI(); if (ABI != ParameterABI::Ordinary) OS << "__attribute__((" << getParameterABISpelling(ABI) << ")) "; diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index c6988b5a9f3..a432c3ca20d 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -455,11 +455,15 @@ const CGFunctionInfo & CodeGenTypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD, QualType receiverType) { SmallVector<CanQualType, 16> argTys; + SmallVector<FunctionProtoType::ExtParameterInfo, 4> extParamInfos(2); argTys.push_back(Context.getCanonicalParamType(receiverType)); argTys.push_back(Context.getCanonicalParamType(Context.getObjCSelType())); // FIXME: Kill copy? for (const auto *I : MD->parameters()) { argTys.push_back(Context.getCanonicalParamType(I->getType())); + auto extParamInfo = FunctionProtoType::ExtParameterInfo().withIsNoEscape( + I->hasAttr<NoEscapeAttr>()); + extParamInfos.push_back(extParamInfo); } FunctionType::ExtInfo einfo; @@ -475,7 +479,7 @@ CodeGenTypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD, return arrangeLLVMFunctionInfo( GetReturnType(MD->getReturnType()), /*instanceMethod=*/false, - /*chainCall=*/false, argTys, einfo, {}, required); + /*chainCall=*/false, argTys, einfo, extParamInfos, required); } const CGFunctionInfo & @@ -2093,6 +2097,9 @@ void CodeGenModule::ConstructAttributeList( break; } + if (FI.getExtParameterInfo(ArgNo).isNoEscape()) + Attrs.addAttribute(llvm::Attribute::NoCapture); + if (Attrs.hasAttributes()) { unsigned FirstIRArg, NumIRArgs; std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index b8432ebd53b..cffb860638d 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1531,6 +1531,22 @@ static void handleReturnsNonNullAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } +static void handleNoEscapeAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (D->isInvalidDecl()) + return; + + // noescape only applies to pointer types. + QualType T = cast<ParmVarDecl>(D)->getType(); + if (!S.isValidPointerAttrType(T, /* RefOkay */ true)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_pointers_only) + << Attr.getName() << Attr.getRange() << 0; + return; + } + + D->addAttr(::new (S.Context) NoEscapeAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); +} + static void handleAssumeAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) { Expr *E = Attr.getArgAsExpr(0), @@ -6167,6 +6183,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_ReturnsNonNull: handleReturnsNonNullAttr(S, D, Attr); break; + case AttributeList::AT_NoEscape: + handleNoEscapeAttr(S, D, Attr); + break; case AttributeList::AT_AssumeAligned: handleAssumeAlignedAttr(S, D, Attr); break; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 529084a517b..312e0e24828 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -14081,8 +14081,21 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) { bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New, const CXXMethodDecl *Old) { - const FunctionType *NewFT = New->getType()->getAs<FunctionType>(); - const FunctionType *OldFT = Old->getType()->getAs<FunctionType>(); + const auto *NewFT = New->getType()->getAs<FunctionProtoType>(); + const auto *OldFT = Old->getType()->getAs<FunctionProtoType>(); + + if (OldFT->hasExtParameterInfos()) { + for (unsigned I = 0, E = OldFT->getNumParams(); I != E; ++I) + // A parameter of the overriding method should be annotated with noescape + // if the corresponding parameter of the overridden method is annotated. + if (OldFT->getExtParameterInfo(I).isNoEscape() && + !NewFT->getExtParameterInfo(I).isNoEscape()) { + Diag(New->getParamDecl(I)->getLocation(), + diag::warn_overriding_method_missing_noescape); + Diag(Old->getParamDecl(I)->getLocation(), + diag::note_overridden_marked_noescape); + } + } CallingConv NewCC = NewFT->getCallConv(), OldCC = OldFT->getCallConv(); diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 5f9f608b75c..6b33f7c64ce 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -188,6 +188,14 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, Diag(newDecl->getLocation(), diag::warn_nsconsumed_attribute_mismatch); Diag(oldDecl->getLocation(), diag::note_previous_decl) << "parameter"; } + + // A parameter of the overriding method should be annotated with noescape + // if the corresponding parameter of the overridden method is annotated. + if (oldDecl->hasAttr<NoEscapeAttr>() && !newDecl->hasAttr<NoEscapeAttr>()) { + Diag(newDecl->getLocation(), + diag::warn_overriding_method_missing_noescape); + Diag(oldDecl->getLocation(), diag::note_overridden_marked_noescape); + } } } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 36f24fd9c46..8f28ec2fb8a 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1481,6 +1481,23 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType, .getTypePtr()); Changed = true; } + + // Convert FromFPT's ExtParameterInfo if necessary. The conversion is valid + // only if the ExtParameterInfo lists of the two function prototypes can be + // merged and the merged list is identical to ToFPT's ExtParameterInfo list. + SmallVector<FunctionProtoType::ExtParameterInfo, 4> NewParamInfos; + bool CanUseToFPT, CanUseFromFPT; + if (Context.mergeExtParameterInfo(ToFPT, FromFPT, CanUseToFPT, + CanUseFromFPT, NewParamInfos) && + CanUseToFPT && !CanUseFromFPT) { + FunctionProtoType::ExtProtoInfo ExtInfo = FromFPT->getExtProtoInfo(); + ExtInfo.ExtParameterInfos = + NewParamInfos.empty() ? nullptr : NewParamInfos.data(); + QualType QT = Context.getFunctionType(FromFPT->getReturnType(), + FromFPT->getParamTypes(), ExtInfo); + FromFn = QT->getAs<FunctionType>(); + Changed = true; + } } if (!Changed) @@ -2663,8 +2680,12 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType, // Argument types are too different. Abort. return false; } - if (!Context.doFunctionTypesMatchOnExtParameterInfos(FromFunctionType, - ToFunctionType)) + + SmallVector<FunctionProtoType::ExtParameterInfo, 4> NewParamInfos; + bool CanUseToFPT, CanUseFromFPT; + if (!Context.mergeExtParameterInfo(ToFunctionType, FromFunctionType, + CanUseToFPT, CanUseFromFPT, + NewParamInfos)) return false; ConvertedType = ToType; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index c4d7bb1f36a..f35eef2d4f7 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -4479,6 +4479,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, HasAnyInterestingExtParameterInfos = true; } + if (Param->hasAttr<NoEscapeAttr>()) { + ExtParameterInfos[i] = ExtParameterInfos[i].withIsNoEscape(true); + HasAnyInterestingExtParameterInfos = true; + } + ParamTys.push_back(ParamTy); } |