diff options
author | dim <dim@FreeBSD.org> | 2015-06-21 14:00:56 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2015-06-21 14:00:56 +0000 |
commit | 9dd834653b811ad20382e98a87dff824980c9916 (patch) | |
tree | a764184c2fc9486979b074250b013a0937ee64e5 /lib/Sema | |
parent | bb9760db9b86e93a638ed430d0a14785f7ff9064 (diff) | |
download | FreeBSD-src-9dd834653b811ad20382e98a87dff824980c9916.zip FreeBSD-src-9dd834653b811ad20382e98a87dff824980c9916.tar.gz |
Vendor import of clang trunk r240225:
https://llvm.org/svn/llvm-project/cfe/trunk@240225
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/AnalysisBasedWarnings.cpp | 17 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 27 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 300 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 71 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 91 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 118 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 168 | ||||
-rw-r--r-- | lib/Sema/SemaExceptionSpec.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 137 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 232 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 133 | ||||
-rw-r--r-- | lib/Sema/SemaObjCProperty.cpp | 115 | ||||
-rw-r--r-- | lib/Sema/SemaOpenMP.cpp | 64 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 53 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaStmtAttr.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 89 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 14 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 840 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 41 |
22 files changed, 2188 insertions, 340 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 97f4a8d..36030b9 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -574,28 +574,29 @@ namespace { /// ContainsReference - A visitor class to search for references to /// a particular declaration (the needle) within any evaluated component of an /// expression (recursively). -class ContainsReference : public EvaluatedExprVisitor<ContainsReference> { +class ContainsReference : public ConstEvaluatedExprVisitor<ContainsReference> { bool FoundReference; const DeclRefExpr *Needle; public: + typedef ConstEvaluatedExprVisitor<ContainsReference> Inherited; + ContainsReference(ASTContext &Context, const DeclRefExpr *Needle) - : EvaluatedExprVisitor<ContainsReference>(Context), - FoundReference(false), Needle(Needle) {} + : Inherited(Context), FoundReference(false), Needle(Needle) {} - void VisitExpr(Expr *E) { + void VisitExpr(const Expr *E) { // Stop evaluating if we already have a reference. if (FoundReference) return; - EvaluatedExprVisitor<ContainsReference>::VisitExpr(E); + Inherited::VisitExpr(E); } - void VisitDeclRefExpr(DeclRefExpr *E) { + void VisitDeclRefExpr(const DeclRefExpr *E) { if (E == Needle) FoundReference = true; else - EvaluatedExprVisitor<ContainsReference>::VisitDeclRefExpr(E); + Inherited::VisitDeclRefExpr(E); } bool doesContainReference() const { return FoundReference; } @@ -854,7 +855,7 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, return false; ContainsReference CR(S.Context, DRE); - CR.Visit(const_cast<Expr*>(Initializer)); + CR.Visit(Initializer); if (CR.doesContainReference()) { S.Diag(DRE->getLocStart(), diag::warn_uninit_self_reference_in_init) diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 50edc42..db1251f 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -356,6 +356,19 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, assert((VK == VK_RValue || !E->isRValue()) && "can't cast rvalue to lvalue"); #endif + // Check whether we're implicitly casting from a nullable type to a nonnull + // type. + if (auto exprNullability = E->getType()->getNullability(Context)) { + if (*exprNullability == NullabilityKind::Nullable) { + if (auto typeNullability = Ty->getNullability(Context)) { + if (*typeNullability == NullabilityKind::NonNull) { + Diag(E->getLocStart(), diag::warn_nullability_lost) + << E->getType() << Ty; + } + } + } + } + QualType ExprTy = Context.getCanonicalType(E->getType()); QualType TypeTy = Context.getCanonicalType(Ty); @@ -551,10 +564,10 @@ static bool MethodsAndNestedClassesComplete(const CXXRecordDecl *RD, if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I)) Complete = M->isDefined() || (M->isPure() && !isa<CXXDestructorDecl>(M)); else if (const FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(*I)) - // If the template function is marked as late template parsed at this point, - // it has not been instantiated and therefore we have not performed semantic - // analysis on it yet, so we cannot know if the type can be considered - // complete. + // If the template function is marked as late template parsed at this + // point, it has not been instantiated and therefore we have not + // performed semantic analysis on it yet, so we cannot know if the type + // can be considered complete. Complete = !F->getTemplatedDecl()->isLateTemplateParsed() && F->getTemplatedDecl()->isDefined(); else if (const CXXRecordDecl *R = dyn_cast<CXXRecordDecl>(*I)) { @@ -722,11 +735,7 @@ void Sema::ActOnEndOfTranslationUnit() { ModMap.resolveConflicts(Mod, /*Complain=*/false); // Queue the submodules, so their exports will also be resolved. - for (Module::submodule_iterator Sub = Mod->submodule_begin(), - SubEnd = Mod->submodule_end(); - Sub != SubEnd; ++Sub) { - Stack.push_back(*Sub); - } + Stack.append(Mod->submodule_begin(), Mod->submodule_end()); } } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index c3b81b6..f76727c 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -836,6 +836,16 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { SemaBuiltinConstantArgRange(TheCall, 2, 0, 1); } + if (BuiltinID == ARM::BI__builtin_arm_rsr64 || + BuiltinID == ARM::BI__builtin_arm_wsr64) + return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 3, false); + + if (BuiltinID == ARM::BI__builtin_arm_rsr || + BuiltinID == ARM::BI__builtin_arm_rsrp || + BuiltinID == ARM::BI__builtin_arm_wsr || + BuiltinID == ARM::BI__builtin_arm_wsrp) + return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); + if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall)) return true; @@ -876,6 +886,16 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, SemaBuiltinConstantArgRange(TheCall, 4, 0, 1); } + if (BuiltinID == AArch64::BI__builtin_arm_rsr64 || + BuiltinID == AArch64::BI__builtin_arm_wsr64) + return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, false); + + if (BuiltinID == AArch64::BI__builtin_arm_rsr || + BuiltinID == AArch64::BI__builtin_arm_rsrp || + BuiltinID == AArch64::BI__builtin_arm_wsr || + BuiltinID == AArch64::BI__builtin_arm_wsrp) + return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); + if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall)) return true; @@ -1095,6 +1115,13 @@ bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, /// \brief Returns true if the value evaluates to null. static bool CheckNonNullExpr(Sema &S, const Expr *Expr) { + // If the expression has non-null type, it doesn't evaluate to null. + if (auto nullability + = Expr->IgnoreImplicit()->getType()->getNullability(S.Context)) { + if (*nullability == NullabilityKind::NonNull) + return false; + } + // As a special case, transparent unions initialized with zero are // considered null for the purposes of the nonnull attribute. if (const RecordType *UT = Expr->getType()->getAsUnionType()) { @@ -1170,56 +1197,111 @@ DiagnoseCStringFormatDirectiveInCFAPI(Sema &S, } } +/// Determine whether the given type has a non-null nullability annotation. +static bool isNonNullType(ASTContext &ctx, QualType type) { + if (auto nullability = type->getNullability(ctx)) + return *nullability == NullabilityKind::NonNull; + + return false; +} + static void CheckNonNullArguments(Sema &S, const NamedDecl *FDecl, + const FunctionProtoType *Proto, ArrayRef<const Expr *> Args, SourceLocation CallSiteLoc) { + assert((FDecl || Proto) && "Need a function declaration or prototype"); + // Check the attributes attached to the method/function itself. llvm::SmallBitVector NonNullArgs; - for (const auto *NonNull : FDecl->specific_attrs<NonNullAttr>()) { - if (!NonNull->args_size()) { - // Easy case: all pointer arguments are nonnull. - for (const auto *Arg : Args) - if (S.isValidPointerAttrType(Arg->getType())) - CheckNonNullArgument(S, Arg, CallSiteLoc); - return; - } + if (FDecl) { + // Handle the nonnull attribute on the function/method declaration itself. + for (const auto *NonNull : FDecl->specific_attrs<NonNullAttr>()) { + if (!NonNull->args_size()) { + // Easy case: all pointer arguments are nonnull. + for (const auto *Arg : Args) + if (S.isValidPointerAttrType(Arg->getType())) + CheckNonNullArgument(S, Arg, CallSiteLoc); + return; + } - for (unsigned Val : NonNull->args()) { - if (Val >= Args.size()) - continue; - if (NonNullArgs.empty()) - NonNullArgs.resize(Args.size()); - NonNullArgs.set(Val); + for (unsigned Val : NonNull->args()) { + if (Val >= Args.size()) + continue; + if (NonNullArgs.empty()) + NonNullArgs.resize(Args.size()); + NonNullArgs.set(Val); + } } } - // Check the attributes on the parameters. - ArrayRef<ParmVarDecl*> parms; - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(FDecl)) - parms = FD->parameters(); - else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(FDecl)) - parms = MD->parameters(); - - unsigned ArgIndex = 0; - for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end(); - I != E; ++I, ++ArgIndex) { - const ParmVarDecl *PVD = *I; - if (PVD->hasAttr<NonNullAttr>() || - (ArgIndex < NonNullArgs.size() && NonNullArgs[ArgIndex])) - CheckNonNullArgument(S, Args[ArgIndex], CallSiteLoc); + if (FDecl && (isa<FunctionDecl>(FDecl) || isa<ObjCMethodDecl>(FDecl))) { + // Handle the nonnull attribute on the parameters of the + // function/method. + ArrayRef<ParmVarDecl*> parms; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(FDecl)) + parms = FD->parameters(); + else + parms = cast<ObjCMethodDecl>(FDecl)->parameters(); + + unsigned ParamIndex = 0; + for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end(); + I != E; ++I, ++ParamIndex) { + const ParmVarDecl *PVD = *I; + if (PVD->hasAttr<NonNullAttr>() || + isNonNullType(S.Context, PVD->getType())) { + if (NonNullArgs.empty()) + NonNullArgs.resize(Args.size()); + + NonNullArgs.set(ParamIndex); + } + } + } else { + // If we have a non-function, non-method declaration but no + // function prototype, try to dig out the function prototype. + if (!Proto) { + if (const ValueDecl *VD = dyn_cast<ValueDecl>(FDecl)) { + QualType type = VD->getType().getNonReferenceType(); + if (auto pointerType = type->getAs<PointerType>()) + type = pointerType->getPointeeType(); + else if (auto blockType = type->getAs<BlockPointerType>()) + type = blockType->getPointeeType(); + // FIXME: data member pointers? + + // Dig out the function prototype, if there is one. + Proto = type->getAs<FunctionProtoType>(); + } + } + + // Fill in non-null argument information from the nullability + // information on the parameter types (if we have them). + if (Proto) { + unsigned Index = 0; + for (auto paramType : Proto->getParamTypes()) { + if (isNonNullType(S.Context, paramType)) { + if (NonNullArgs.empty()) + NonNullArgs.resize(Args.size()); + + NonNullArgs.set(Index); + } + + ++Index; + } + } } - // In case this is a variadic call, check any remaining arguments. - for (/**/; ArgIndex < NonNullArgs.size(); ++ArgIndex) + // Check for non-null arguments. + for (unsigned ArgIndex = 0, ArgIndexEnd = NonNullArgs.size(); + ArgIndex != ArgIndexEnd; ++ArgIndex) { if (NonNullArgs[ArgIndex]) CheckNonNullArgument(S, Args[ArgIndex], CallSiteLoc); + } } /// Handles the checks for format strings, non-POD arguments to vararg /// functions, and NULL arguments passed to non-NULL parameters. -void Sema::checkCall(NamedDecl *FDecl, ArrayRef<const Expr *> Args, - unsigned NumParams, bool IsMemberFunction, +void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, + ArrayRef<const Expr *> Args, bool IsMemberFunction, SourceLocation Loc, SourceRange Range, VariadicCallType CallType) { // FIXME: We should check as much as we can in the template definition. @@ -1241,6 +1323,13 @@ void Sema::checkCall(NamedDecl *FDecl, ArrayRef<const Expr *> Args, // Refuse POD arguments that weren't caught by the format string // checks above. if (CallType != VariadicDoesNotApply) { + unsigned NumParams = Proto ? Proto->getNumParams() + : FDecl && isa<FunctionDecl>(FDecl) + ? cast<FunctionDecl>(FDecl)->getNumParams() + : FDecl && isa<ObjCMethodDecl>(FDecl) + ? cast<ObjCMethodDecl>(FDecl)->param_size() + : 0; + for (unsigned ArgIdx = NumParams; ArgIdx < Args.size(); ++ArgIdx) { // Args[ArgIdx] can be null in malformed code. if (const Expr *Arg = Args[ArgIdx]) { @@ -1250,12 +1339,14 @@ void Sema::checkCall(NamedDecl *FDecl, ArrayRef<const Expr *> Args, } } - if (FDecl) { - CheckNonNullArguments(*this, FDecl, Args, Loc); + if (FDecl || Proto) { + CheckNonNullArguments(*this, FDecl, Proto, Args, Loc); // Type safety checking. - for (const auto *I : FDecl->specific_attrs<ArgumentWithTypeTagAttr>()) - CheckArgumentWithTypeTag(I, Args.data()); + if (FDecl) { + for (const auto *I : FDecl->specific_attrs<ArgumentWithTypeTagAttr>()) + CheckArgumentWithTypeTag(I, Args.data()); + } } } @@ -1267,8 +1358,8 @@ void Sema::CheckConstructorCall(FunctionDecl *FDecl, SourceLocation Loc) { VariadicCallType CallType = Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply; - checkCall(FDecl, Args, Proto->getNumParams(), - /*IsMemberFunction=*/true, Loc, SourceRange(), CallType); + checkCall(FDecl, Proto, Args, /*IsMemberFunction=*/true, Loc, SourceRange(), + CallType); } /// CheckFunctionCall - Check a direct function call for various correctness @@ -1281,7 +1372,6 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, IsMemberOperatorCall; VariadicCallType CallType = getVariadicCallType(FDecl, Proto, TheCall->getCallee()); - unsigned NumParams = Proto ? Proto->getNumParams() : 0; Expr** Args = TheCall->getArgs(); unsigned NumArgs = TheCall->getNumArgs(); if (IsMemberOperatorCall) { @@ -1291,7 +1381,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, ++Args; --NumArgs; } - checkCall(FDecl, llvm::makeArrayRef(Args, NumArgs), NumParams, + checkCall(FDecl, Proto, llvm::makeArrayRef(Args, NumArgs), IsMemberFunction, TheCall->getRParenLoc(), TheCall->getCallee()->getSourceRange(), CallType); @@ -1325,9 +1415,9 @@ bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac, VariadicCallType CallType = Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply; - checkCall(Method, Args, Method->param_size(), - /*IsMemberFunction=*/false, - lbrac, Method->getSourceRange(), CallType); + checkCall(Method, nullptr, Args, + /*IsMemberFunction=*/false, lbrac, Method->getSourceRange(), + CallType); return false; } @@ -1336,13 +1426,14 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, const FunctionProtoType *Proto) { QualType Ty; if (const auto *V = dyn_cast<VarDecl>(NDecl)) - Ty = V->getType(); + Ty = V->getType().getNonReferenceType(); else if (const auto *F = dyn_cast<FieldDecl>(NDecl)) - Ty = F->getType(); + Ty = F->getType().getNonReferenceType(); else return false; - if (!Ty->isBlockPointerType() && !Ty->isFunctionPointerType()) + if (!Ty->isBlockPointerType() && !Ty->isFunctionPointerType() && + !Ty->isFunctionProtoType()) return false; VariadicCallType CallType; @@ -1353,11 +1444,10 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, } else { // Ty->isFunctionPointerType() CallType = VariadicFunction; } - unsigned NumParams = Proto ? Proto->getNumParams() : 0; - checkCall(NDecl, llvm::makeArrayRef(TheCall->getArgs(), - TheCall->getNumArgs()), - NumParams, /*IsMemberFunction=*/false, TheCall->getRParenLoc(), + checkCall(NDecl, Proto, + llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()), + /*IsMemberFunction=*/false, TheCall->getRParenLoc(), TheCall->getCallee()->getSourceRange(), CallType); return false; @@ -1368,11 +1458,9 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) { VariadicCallType CallType = getVariadicCallType(/*FDecl=*/nullptr, Proto, TheCall->getCallee()); - unsigned NumParams = Proto ? Proto->getNumParams() : 0; - - checkCall(/*FDecl=*/nullptr, + checkCall(/*FDecl=*/nullptr, Proto, llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()), - NumParams, /*IsMemberFunction=*/false, TheCall->getRParenLoc(), + /*IsMemberFunction=*/false, TheCall->getRParenLoc(), TheCall->getCallee()->getSourceRange(), CallType); return false; @@ -2593,6 +2681,107 @@ bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, return false; } +/// SemaBuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr +/// TheCall is an ARM/AArch64 special register string literal. +bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, + int ArgNum, unsigned ExpectedFieldNum, + bool AllowName) { + bool IsARMBuiltin = BuiltinID == ARM::BI__builtin_arm_rsr64 || + BuiltinID == ARM::BI__builtin_arm_wsr64 || + BuiltinID == ARM::BI__builtin_arm_rsr || + BuiltinID == ARM::BI__builtin_arm_rsrp || + BuiltinID == ARM::BI__builtin_arm_wsr || + BuiltinID == ARM::BI__builtin_arm_wsrp; + bool IsAArch64Builtin = BuiltinID == AArch64::BI__builtin_arm_rsr64 || + BuiltinID == AArch64::BI__builtin_arm_wsr64 || + BuiltinID == AArch64::BI__builtin_arm_rsr || + BuiltinID == AArch64::BI__builtin_arm_rsrp || + BuiltinID == AArch64::BI__builtin_arm_wsr || + BuiltinID == AArch64::BI__builtin_arm_wsrp; + assert((IsARMBuiltin || IsAArch64Builtin) && "Unexpected ARM builtin."); + + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check if the argument is a string literal. + if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts())) + return Diag(TheCall->getLocStart(), diag::err_expr_not_string_literal) + << Arg->getSourceRange(); + + // Check the type of special register given. + StringRef Reg = cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString(); + SmallVector<StringRef, 6> Fields; + Reg.split(Fields, ":"); + + if (Fields.size() != ExpectedFieldNum && !(AllowName && Fields.size() == 1)) + return Diag(TheCall->getLocStart(), diag::err_arm_invalid_specialreg) + << Arg->getSourceRange(); + + // If the string is the name of a register then we cannot check that it is + // valid here but if the string is of one the forms described in ACLE then we + // can check that the supplied fields are integers and within the valid + // ranges. + if (Fields.size() > 1) { + bool FiveFields = Fields.size() == 5; + + bool ValidString = true; + if (IsARMBuiltin) { + ValidString &= Fields[0].startswith_lower("cp") || + Fields[0].startswith_lower("p"); + if (ValidString) + Fields[0] = + Fields[0].drop_front(Fields[0].startswith_lower("cp") ? 2 : 1); + + ValidString &= Fields[2].startswith_lower("c"); + if (ValidString) + Fields[2] = Fields[2].drop_front(1); + + if (FiveFields) { + ValidString &= Fields[3].startswith_lower("c"); + if (ValidString) + Fields[3] = Fields[3].drop_front(1); + } + } + + SmallVector<int, 5> Ranges; + if (FiveFields) + Ranges.append({IsAArch64Builtin ? 1 : 15, 7, 7, 15, 15}); + else + Ranges.append({15, 7, 15}); + + for (unsigned i=0; i<Fields.size(); ++i) { + int IntField; + ValidString &= !Fields[i].getAsInteger(10, IntField); + ValidString &= (IntField >= 0 && IntField <= Ranges[i]); + } + + if (!ValidString) + return Diag(TheCall->getLocStart(), diag::err_arm_invalid_specialreg) + << Arg->getSourceRange(); + + } else if (IsAArch64Builtin && Fields.size() == 1) { + // If the register name is one of those that appear in the condition below + // and the special register builtin being used is one of the write builtins, + // then we require that the argument provided for writing to the register + // is an integer constant expression. This is because it will be lowered to + // an MSR (immediate) instruction, so we need to know the immediate at + // compile time. + if (TheCall->getNumArgs() != 2) + return false; + + std::string RegLower = Reg.lower(); + if (RegLower != "spsel" && RegLower != "daifset" && RegLower != "daifclr" && + RegLower != "pan" && RegLower != "uao") + return false; + + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + } + + return false; +} + /// SemaBuiltinLongjmp - Handle __builtin_longjmp(void *env[5], int val). /// This checks that the target supports __builtin_longjmp and /// that val is a constant 1. @@ -5559,7 +5748,8 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, CheckReturnStackAddr(*this, RetValExp, lhsType, ReturnLoc); // Check if the return value is null but should not be. - if (Attrs && hasSpecificAttr<ReturnsNonNullAttr>(*Attrs) && + if (((Attrs && hasSpecificAttr<ReturnsNonNullAttr>(*Attrs)) || + (!isObjCMethod && isNonNullType(Context, lhsType))) && CheckNonNullExpr(*this, RetValExp)) Diag(ReturnLoc, diag::warn_null_ret) << (isObjCMethod ? 1 : 0) << RetValExp->getSourceRange(); diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index fd97809..ebb6bbc 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -1341,6 +1341,11 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); } + + // Nullability + Results.AddResult(Result("__nonnull", CCP_Type)); + Results.AddResult(Result("__null_unspecified", CCP_Type)); + Results.AddResult(Result("__nullable", CCP_Type)); } static void AddStorageSpecifiers(Sema::ParserCompletionContext CCC, @@ -2097,7 +2102,8 @@ static void MaybeAddSentinel(Preprocessor &PP, } } -static std::string formatObjCParamQualifiers(unsigned ObjCQuals) { +static std::string formatObjCParamQualifiers(unsigned ObjCQuals, + QualType &Type) { std::string Result; if (ObjCQuals & Decl::OBJC_TQ_In) Result += "in "; @@ -2111,6 +2117,23 @@ static std::string formatObjCParamQualifiers(unsigned ObjCQuals) { Result += "byref "; if (ObjCQuals & Decl::OBJC_TQ_Oneway) Result += "oneway "; + if (ObjCQuals & Decl::OBJC_TQ_CSNullability) { + if (auto nullability = AttributedType::stripOuterNullability(Type)) { + switch (*nullability) { + case NullabilityKind::NonNull: + Result += "nonnull "; + break; + + case NullabilityKind::Nullable: + Result += "nullable "; + break; + + case NullabilityKind::Unspecified: + Result += "null_unspecified "; + break; + } + } + } return Result; } @@ -2128,13 +2151,15 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, if (Param->getIdentifier() && !ObjCMethodParam && !SuppressName) Result = Param->getIdentifier()->getName(); - Param->getType().getAsStringInternal(Result, Policy); - + QualType Type = Param->getType(); if (ObjCMethodParam) { - Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier()) - + Result + ")"; + Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier(), + Type); + Result += Type.getAsString(Policy) + ")"; if (Param->getIdentifier() && !SuppressName) Result += Param->getIdentifier()->getName(); + } else { + Type.getAsStringInternal(Result, Policy); } return Result; } @@ -2182,13 +2207,16 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, if (!ObjCMethodParam && Param->getIdentifier()) Result = Param->getIdentifier()->getName(); - Param->getType().getUnqualifiedType().getAsStringInternal(Result, Policy); + QualType Type = Param->getType().getUnqualifiedType(); if (ObjCMethodParam) { - Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier()) - + Result + ")"; + Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier(), + Type); + Result += Type.getAsString(Policy) + Result + ")"; if (Param->getIdentifier()) Result += Param->getIdentifier()->getName(); + } else { + Type.getAsStringInternal(Result, Policy); } return Result; @@ -2762,9 +2790,10 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, if ((*P)->getType()->isBlockPointerType() && !DeclaringEntity) Arg = FormatFunctionParameter(Policy, *P, true); else { - (*P)->getType().getAsStringInternal(Arg, Policy); - Arg = "(" + formatObjCParamQualifiers((*P)->getObjCDeclQualifier()) - + Arg + ")"; + QualType Type = (*P)->getType(); + Arg = "(" + formatObjCParamQualifiers((*P)->getObjCDeclQualifier(), + Type); + Arg += Type.getAsString(Policy) + ")"; if (IdentifierInfo *II = (*P)->getIdentifier()) if (DeclaringEntity || AllParametersAreInformative) Arg += II->getName(); @@ -4858,6 +4887,12 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { Getter.AddPlaceholderChunk("method"); Results.AddResult(CodeCompletionResult(Getter.TakeString())); } + if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nullability)) { + Results.AddResult(CodeCompletionResult("nonnull")); + Results.AddResult(CodeCompletionResult("nullable")); + Results.AddResult(CodeCompletionResult("null_unspecified")); + Results.AddResult(CodeCompletionResult("null_resettable")); + } Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Other, @@ -5107,6 +5142,11 @@ void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS, Results.AddResult("byref"); Results.AddResult("oneway"); } + if ((DS.getObjCDeclQualifier() & ObjCDeclSpec::DQ_CSNullability) == 0) { + Results.AddResult("nonnull"); + Results.AddResult("nullable"); + Results.AddResult("null_unspecified"); + } // If we're completing the return type of an Objective-C method and the // identifier IBAction refers to a macro, provide a completion item for @@ -6279,7 +6319,7 @@ static void AddObjCPassingTypeChunk(QualType Type, const PrintingPolicy &Policy, CodeCompletionBuilder &Builder) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); - std::string Quals = formatObjCParamQualifiers(ObjCDeclQuals); + std::string Quals = formatObjCParamQualifiers(ObjCDeclQuals, Type); if (!Quals.empty()) Builder.AddTextChunk(Builder.getAllocator().CopyString(Quals)); Builder.AddTextChunk(GetCompletionTypeString(Type, Context, Policy, @@ -7018,7 +7058,12 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, break; // Add the parameter type. - AddObjCPassingTypeChunk((*P)->getOriginalType(), + QualType ParamType; + if ((*P)->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) + ParamType = (*P)->getType(); + else + ParamType = (*P)->getOriginalType(); + AddObjCPassingTypeChunk(ParamType, (*P)->getObjCDeclQualifier(), Context, Policy, Builder); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 89f4b3a..aa006b3 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1007,7 +1007,7 @@ Corrected: // Check for a tag type hidden by a non-type decl in a few cases where it // seems likely a type is wanted instead of the non-type that was found. - bool NextIsOp = NextToken.is(tok::amp) || NextToken.is(tok::star); + bool NextIsOp = NextToken.isOneOf(tok::amp, tok::star); if ((NextToken.is(tok::identifier) || (NextIsOp && FirstDecl->getUnderlyingDecl()->isFunctionOrFunctionTemplate())) && @@ -1081,6 +1081,22 @@ void Sema::PopDeclContext() { assert(CurContext && "Popped translation unit!"); } +Sema::SkippedDefinitionContext Sema::ActOnTagStartSkippedDefinition(Scope *S, + Decl *D) { + // Unlike PushDeclContext, the context to which we return is not necessarily + // the containing DC of TD, because the new context will be some pre-existing + // TagDecl definition instead of a fresh one. + auto Result = static_cast<SkippedDefinitionContext>(CurContext); + CurContext = cast<TagDecl>(D)->getDefinition(); + assert(CurContext && "skipping definition of undefined tag"); + S->setEntity(CurContext); + return Result; +} + +void Sema::ActOnTagFinishSkippedDefinition(SkippedDefinitionContext Context) { + CurContext = static_cast<decltype(CurContext)>(Context); +} + /// EnterDeclaratorContext - Used when we must lookup names in the context /// of a declarator's nested name specifier. /// @@ -1788,7 +1804,7 @@ static void filterNonConflictingPreviousDecls(Sema &S, NamedDecl *decl, LookupResult &previous){ // This is only interesting when modules are enabled. - if (!S.getLangOpts().Modules) + if (!S.getLangOpts().Modules && !S.getLangOpts().ModulesLocalVisibility) return; // Empty sets are uninteresting. @@ -1818,7 +1834,7 @@ static void filterNonConflictingPreviousTypedefDecls(Sema &S, TypedefNameDecl *Decl, LookupResult &Previous) { // This is only interesting when modules are enabled. - if (!S.getLangOpts().Modules) + if (!S.getLangOpts().Modules && !S.getLangOpts().ModulesLocalVisibility) return; // Empty sets are uninteresting. @@ -2449,6 +2465,32 @@ static void mergeParamDeclAttributes(ParmVarDecl *newDecl, if (!foundAny) newDecl->dropAttrs(); } +static void mergeParamDeclTypes(ParmVarDecl *NewParam, + const ParmVarDecl *OldParam, + Sema &S) { + if (auto Oldnullability = OldParam->getType()->getNullability(S.Context)) { + if (auto Newnullability = NewParam->getType()->getNullability(S.Context)) { + if (*Oldnullability != *Newnullability) { + unsigned unsNewnullability = static_cast<unsigned>(*Newnullability); + unsigned unsOldnullability = static_cast<unsigned>(*Oldnullability); + S.Diag(NewParam->getLocation(), diag::warn_mismatched_nullability_attr) + << unsNewnullability + << ((NewParam->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) != 0) + << unsOldnullability + << ((OldParam->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) != 0); + S.Diag(OldParam->getLocation(), diag::note_previous_declaration); + } + } + else { + QualType NewT = NewParam->getType(); + NewT = S.Context.getAttributedType( + AttributedType::getNullabilityAttrKind(*Oldnullability), + NewT, NewT); + NewParam->setType(NewT); + } + } +} + namespace { /// Used in MergeFunctionDecl to keep track of function parameters in @@ -3085,9 +3127,12 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old, // Merge attributes from the parameters. These can mismatch with K&R // declarations. if (New->getNumParams() == Old->getNumParams()) - for (unsigned i = 0, e = New->getNumParams(); i != e; ++i) - mergeParamDeclAttributes(New->getParamDecl(i), Old->getParamDecl(i), - *this); + for (unsigned i = 0, e = New->getNumParams(); i != e; ++i) { + ParmVarDecl *NewParam = New->getParamDecl(i); + ParmVarDecl *OldParam = Old->getParamDecl(i); + mergeParamDeclAttributes(NewParam, OldParam, *this); + mergeParamDeclTypes(NewParam, OldParam, *this); + } if (getLangOpts().CPlusPlus) return MergeCXXFunctionDecl(New, Old, S); @@ -4663,12 +4708,14 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, RequireCompleteDeclContext(D.getCXXScopeSpec(), DC)) return nullptr; + // If a class is incomplete, do not parse entities inside it. if (isa<CXXRecordDecl>(DC) && !cast<CXXRecordDecl>(DC)->hasDefinition()) { Diag(D.getIdentifierLoc(), diag::err_member_def_undefined_record) << Name << DC << D.getCXXScopeSpec().getRange(); - D.setInvalidType(); - } else if (!D.getDeclSpec().isFriendSpecified()) { + return nullptr; + } + if (!D.getDeclSpec().isFriendSpecified()) { if (diagnoseQualifiedDeclaration(D.getCXXScopeSpec(), DC, Name, D.getIdentifierLoc())) { if (DC->isRecord()) @@ -13486,7 +13533,8 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, Sema::SkipBodyInfo Sema::shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II, SourceLocation IILoc) { - if (!getLangOpts().Modules || !getLangOpts().CPlusPlus) + if (!(getLangOpts().Modules || getLangOpts().ModulesLocalVisibility) || + !getLangOpts().CPlusPlus) return SkipBodyInfo(); // We have an anonymous enum definition. Look up the first enumerator to @@ -13500,7 +13548,6 @@ Sema::SkipBodyInfo Sema::shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II, !hasVisibleDefinition(cast<NamedDecl>(PrevECD->getDeclContext()), &Hidden)) { SkipBodyInfo Skip; - Skip.ShouldSkip = true; Skip.Previous = Hidden; return Skip; } @@ -14197,16 +14244,22 @@ void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name, SourceLocation PragmaLoc, SourceLocation NameLoc, SourceLocation AliasNameLoc) { - Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, - LookupOrdinaryName); - AsmLabelAttr *Attr = ::new (Context) AsmLabelAttr(AliasNameLoc, Context, - AliasName->getName(), 0); - - if (PrevDecl) + NamedDecl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, + LookupOrdinaryName); + AsmLabelAttr *Attr = + AsmLabelAttr::CreateImplicit(Context, AliasName->getName(), AliasNameLoc); + + // If a declaration that: + // 1) declares a function or a variable + // 2) has external linkage + // already exists, add a label attribute to it. + if (PrevDecl && + (isa<FunctionDecl>(PrevDecl) || isa<VarDecl>(PrevDecl)) && + PrevDecl->hasExternalFormalLinkage()) PrevDecl->addAttr(Attr); - else - (void)ExtnameUndeclaredIdentifiers.insert( - std::pair<IdentifierInfo*,AsmLabelAttr*>(Name, Attr)); + // Otherwise, add a label atttibute to ExtnameUndeclaredIdentifiers. + else + (void)ExtnameUndeclaredIdentifiers.insert(std::make_pair(Name, Attr)); } void Sema::ActOnPragmaWeakID(IdentifierInfo* Name, diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 1d04159..43790c2 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -2397,6 +2397,28 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) { D->addAttr(NewAttr); } +// Check for things we'd like to warn about, no errors or validation for now. +// TODO: Validation should use a backend target library that specifies +// the allowable subtarget features and cpus. We could use something like a +// TargetCodeGenInfo hook here to do validation. +void Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { + for (auto Str : {"tune=", "fpmath="}) + if (AttrStr.find(Str) != StringRef::npos) + Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Str; +} + +static void handleTargetAttr(Sema &S, Decl *D, const AttributeList &Attr) { + StringRef Str; + SourceLocation LiteralLoc; + if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc)) + return; + S.checkTargetAttr(LiteralLoc, Str); + unsigned Index = Attr.getAttributeSpellingListIndex(); + TargetAttr *NewAttr = + ::new (S.Context) TargetAttr(Attr.getRange(), S.Context, Str, Index); + D->addAttr(NewAttr); +} + static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { VarDecl *VD = cast<VarDecl>(D); @@ -3132,16 +3154,22 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - if (!OldTy->getAs<BuiltinType>() && !OldTy->isComplexType()) + // Base type can also be a vector type (see PR17453). + // Distinguish between base type and base element type. + QualType OldElemTy = OldTy; + if (const VectorType *VT = OldTy->getAs<VectorType>()) + OldElemTy = VT->getElementType(); + + if (!OldElemTy->getAs<BuiltinType>() && !OldElemTy->isComplexType()) S.Diag(Attr.getLoc(), diag::err_mode_not_primitive); else if (IntegerMode) { - if (!OldTy->isIntegralOrEnumerationType()) + if (!OldElemTy->isIntegralOrEnumerationType()) S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); } else if (ComplexMode) { - if (!OldTy->isComplexType()) + if (!OldElemTy->isComplexType()) S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); } else { - if (!OldTy->isFloatingType()) + if (!OldElemTy->isFloatingType()) S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); } @@ -3154,21 +3182,40 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - QualType NewTy; + QualType NewElemTy; if (IntegerMode) - NewTy = S.Context.getIntTypeForBitwidth(DestWidth, - OldTy->isSignedIntegerType()); + NewElemTy = S.Context.getIntTypeForBitwidth( + DestWidth, OldElemTy->isSignedIntegerType()); else - NewTy = S.Context.getRealTypeForBitwidth(DestWidth); + NewElemTy = S.Context.getRealTypeForBitwidth(DestWidth); - if (NewTy.isNull()) { + if (NewElemTy.isNull()) { S.Diag(Attr.getLoc(), diag::err_machine_mode) << 1 /*Unsupported*/ << Name; return; } if (ComplexMode) { - NewTy = S.Context.getComplexType(NewTy); + NewElemTy = S.Context.getComplexType(NewElemTy); + } + + QualType NewTy = NewElemTy; + if (const VectorType *OldVT = OldTy->getAs<VectorType>()) { + // Complex machine mode does not support base vector types. + if (ComplexMode) { + S.Diag(Attr.getLoc(), diag::err_complex_mode_vector_type); + return; + } + unsigned NumElements = S.Context.getTypeSize(OldElemTy) * + OldVT->getNumElements() / + S.Context.getTypeSize(NewElemTy); + NewTy = + S.Context.getVectorType(NewElemTy, NumElements, OldVT->getVectorKind()); + } + + if (NewTy.isNull()) { + S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); + return; } // Install the new type. @@ -3683,10 +3730,31 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, returnType = PD->getType(); else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) returnType = FD->getReturnType(); - else { + else if (auto *Param = dyn_cast<ParmVarDecl>(D)) { + returnType = Param->getType()->getPointeeType(); + if (returnType.isNull()) { + S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) + << Attr.getName() << /*pointer-to-CF*/2 + << Attr.getRange(); + return; + } + } else { + AttributeDeclKind ExpectedDeclKind; + switch (Attr.getKind()) { + default: llvm_unreachable("invalid ownership attribute"); + case AttributeList::AT_NSReturnsRetained: + case AttributeList::AT_NSReturnsAutoreleased: + case AttributeList::AT_NSReturnsNotRetained: + ExpectedDeclKind = ExpectedFunctionOrMethod; + break; + + case AttributeList::AT_CFReturnsRetained: + case AttributeList::AT_CFReturnsNotRetained: + ExpectedDeclKind = ExpectedFunctionMethodOrParameter; + break; + } S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) - << Attr.getRange() << Attr.getName() - << ExpectedFunctionOrMethod; + << Attr.getRange() << Attr.getName() << ExpectedDeclKind; return; } @@ -3713,8 +3781,25 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, } if (!typeOK) { - S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type) - << Attr.getRange() << Attr.getName() << isa<ObjCMethodDecl>(D) << cf; + if (isa<ParmVarDecl>(D)) { + S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) + << Attr.getName() << /*pointer-to-CF*/2 + << Attr.getRange(); + } else { + // Needs to be kept in sync with warn_ns_attribute_wrong_return_type. + enum : unsigned { + Function, + Method, + Property + } SubjectKind = Function; + if (isa<ObjCMethodDecl>(D)) + SubjectKind = Method; + else if (isa<ObjCPropertyDecl>(D)) + SubjectKind = Property; + S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type) + << Attr.getName() << SubjectKind << cf + << Attr.getRange(); + } return; } @@ -4716,6 +4801,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_Section: handleSectionAttr(S, D, Attr); break; + case AttributeList::AT_Target: + handleTargetAttr(S, D, Attr); + break; case AttributeList::AT_Unavailable: handleAttrWithMessage<UnavailableAttr>(S, D, Attr); break; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index c80ef2d..7ed9bfc 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -9494,6 +9494,7 @@ static void getDefaultArgExprsForConstructors(Sema &S, CXXRecordDecl *Class) { Expr *DefaultArg = S.BuildCXXDefaultArgExpr(Class->getLocation(), CD, CD->getParamDecl(I)).get(); + S.DiscardCleanupsInEvaluationContext(); S.Context.addDefaultArgExprForConstructor(CD, I, DefaultArg); } } diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 3831879..543566f 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -1366,6 +1366,13 @@ static SourceRange getTypeRange(TypeSourceInfo *TSI) { return (TSI ? TSI->getTypeLoc().getSourceRange() : SourceRange()); } +/// Determine whether two set of Objective-C declaration qualifiers conflict. +static bool objcModifiersConflict(Decl::ObjCDeclQualifier x, + Decl::ObjCDeclQualifier y) { + return (x & ~Decl::OBJC_TQ_CSNullability) != + (y & ~Decl::OBJC_TQ_CSNullability); +} + static bool CheckMethodOverrideReturn(Sema &S, ObjCMethodDecl *MethodImpl, ObjCMethodDecl *MethodDecl, @@ -1373,8 +1380,8 @@ static bool CheckMethodOverrideReturn(Sema &S, bool IsOverridingMode, bool Warn) { if (IsProtocolMethodDecl && - (MethodDecl->getObjCDeclQualifier() != - MethodImpl->getObjCDeclQualifier())) { + objcModifiersConflict(MethodDecl->getObjCDeclQualifier(), + MethodImpl->getObjCDeclQualifier())) { if (Warn) { S.Diag(MethodImpl->getLocation(), (IsOverridingMode @@ -1388,7 +1395,24 @@ static bool CheckMethodOverrideReturn(Sema &S, else return false; } - + if (Warn && IsOverridingMode && + !isa<ObjCImplementationDecl>(MethodImpl->getDeclContext()) && + !S.Context.hasSameNullabilityTypeQualifier(MethodImpl->getReturnType(), + MethodDecl->getReturnType(), + false)) { + unsigned unsNullabilityMethodImpl = + static_cast<unsigned>(*MethodImpl->getReturnType()->getNullability(S.Context)); + unsigned unsNullabilityMethodDecl = + static_cast<unsigned>(*MethodDecl->getReturnType()->getNullability(S.Context)); + S.Diag(MethodImpl->getLocation(), + diag::warn_conflicting_nullability_attr_overriding_ret_types) + << unsNullabilityMethodImpl + << ((MethodImpl->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) != 0) + << unsNullabilityMethodDecl + << ((MethodDecl->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) != 0); + S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration); + } + if (S.Context.hasSameUnqualifiedType(MethodImpl->getReturnType(), MethodDecl->getReturnType())) return true; @@ -1438,8 +1462,8 @@ static bool CheckMethodOverrideParam(Sema &S, bool IsOverridingMode, bool Warn) { if (IsProtocolMethodDecl && - (ImplVar->getObjCDeclQualifier() != - IfaceVar->getObjCDeclQualifier())) { + objcModifiersConflict(ImplVar->getObjCDeclQualifier(), + IfaceVar->getObjCDeclQualifier())) { if (Warn) { if (IsOverridingMode) S.Diag(ImplVar->getLocation(), @@ -1459,7 +1483,19 @@ static bool CheckMethodOverrideParam(Sema &S, QualType ImplTy = ImplVar->getType(); QualType IfaceTy = IfaceVar->getType(); - + if (Warn && IsOverridingMode && + !isa<ObjCImplementationDecl>(MethodImpl->getDeclContext()) && + !S.Context.hasSameNullabilityTypeQualifier(ImplTy, IfaceTy, true)) { + unsigned unsImplTy = static_cast<unsigned>(*ImplTy->getNullability(S.Context)); + unsigned unsIfaceTy = static_cast<unsigned>(*IfaceTy->getNullability(S.Context)); + S.Diag(ImplVar->getLocation(), + diag::warn_conflicting_nullability_attr_overriding_param_types) + << unsImplTy + << ((ImplVar->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) != 0) + << unsIfaceTy + << ((IfaceVar->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) != 0); + S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration); + } if (S.Context.hasSameUnqualifiedType(ImplTy, IfaceTy)) return true; @@ -1988,6 +2024,9 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, SynthesizeProperties); } + // Diagnose null-resettable synthesized setters. + diagnoseNullResettableSynthesizedSetters(IMPDecl); + SelectorSet ClsMap; for (const auto *I : IMPDecl->class_methods()) ClsMap.insert(I->getSelector()); @@ -3121,6 +3160,89 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, ObjCMethod->setOverriding(hasOverriddenMethodsInBaseOrProtocol); } +/// Merge type nullability from for a redeclaration of the same entity, +/// producing the updated type of the redeclared entity. +static QualType mergeTypeNullabilityForRedecl(Sema &S, SourceLocation loc, + QualType type, + bool usesCSKeyword, + SourceLocation prevLoc, + QualType prevType, + bool prevUsesCSKeyword) { + // Determine the nullability of both types. + auto nullability = type->getNullability(S.Context); + auto prevNullability = prevType->getNullability(S.Context); + + // Easy case: both have nullability. + if (nullability.hasValue() == prevNullability.hasValue()) { + // Neither has nullability; continue. + if (!nullability) + return type; + + // The nullabilities are equivalent; do nothing. + if (*nullability == *prevNullability) + return type; + + // Complain about mismatched nullability. + S.Diag(loc, diag::err_nullability_conflicting) + << static_cast<unsigned>(*nullability) << usesCSKeyword + << static_cast<unsigned>(*prevNullability) << prevUsesCSKeyword; + return type; + } + + // If it's the redeclaration that has nullability, don't change anything. + if (nullability) + return type; + + // Otherwise, provide the result with the same nullability. + return S.Context.getAttributedType( + AttributedType::getNullabilityAttrKind(*prevNullability), + type, type); +} + +/// Merge information from the declaration of a method in the \@interface +/// (or a category/extension) into the corresponding method in the +/// @implementation (for a class or category). +static void mergeInterfaceMethodToImpl(Sema &S, + ObjCMethodDecl *method, + ObjCMethodDecl *prevMethod) { + // Merge the objc_requires_super attribute. + if (prevMethod->hasAttr<ObjCRequiresSuperAttr>() && + !method->hasAttr<ObjCRequiresSuperAttr>()) { + // merge the attribute into implementation. + method->addAttr( + ObjCRequiresSuperAttr::CreateImplicit(S.Context, + method->getLocation())); + } + + // Merge nullability of the result type. + QualType newReturnType + = mergeTypeNullabilityForRedecl( + S, method->getReturnTypeSourceRange().getBegin(), + method->getReturnType(), + method->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability, + prevMethod->getReturnTypeSourceRange().getBegin(), + prevMethod->getReturnType(), + prevMethod->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability); + method->setReturnType(newReturnType); + + // Handle each of the parameters. + unsigned numParams = method->param_size(); + unsigned numPrevParams = prevMethod->param_size(); + for (unsigned i = 0, n = std::min(numParams, numPrevParams); i != n; ++i) { + ParmVarDecl *param = method->param_begin()[i]; + ParmVarDecl *prevParam = prevMethod->param_begin()[i]; + + // Merge nullability. + QualType newParamType + = mergeTypeNullabilityForRedecl( + S, param->getLocation(), param->getType(), + param->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability, + prevParam->getLocation(), prevParam->getType(), + prevParam->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability); + param->setType(newParamType); + } +} + Decl *Sema::ActOnMethodDeclaration( Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc, @@ -3151,7 +3273,9 @@ Decl *Sema::ActOnMethodDeclaration( if (CheckFunctionReturnType(resultDeclType, MethodLoc)) return nullptr; - HasRelatedResultType = (resultDeclType == Context.getObjCInstanceType()); + QualType bareResultType = resultDeclType; + (void)AttributedType::stripOuterNullability(bareResultType); + HasRelatedResultType = (bareResultType == Context.getObjCInstanceType()); } else { // get the type for "id". resultDeclType = Context.getObjCIdType(); Diag(MethodLoc, diag::warn_missing_method_return_type) @@ -3252,22 +3376,20 @@ Decl *Sema::ActOnMethodDeclaration( ImpDecl->addClassMethod(ObjCMethod); } - ObjCMethodDecl *IMD = nullptr; - if (ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface()) - IMD = IDecl->lookupMethod(ObjCMethod->getSelector(), - ObjCMethod->isInstanceMethod()); - if (IMD && IMD->hasAttr<ObjCRequiresSuperAttr>() && - !ObjCMethod->hasAttr<ObjCRequiresSuperAttr>()) { - // merge the attribute into implementation. - ObjCMethod->addAttr(ObjCRequiresSuperAttr::CreateImplicit(Context, - ObjCMethod->getLocation())); - } - if (isa<ObjCCategoryImplDecl>(ImpDecl)) { - ObjCMethodFamily family = - ObjCMethod->getSelector().getMethodFamily(); - if (family == OMF_dealloc && IMD && IMD->isOverriding()) - Diag(ObjCMethod->getLocation(), diag::warn_dealloc_in_category) - << ObjCMethod->getDeclName(); + // Merge information from the @interface declaration into the + // @implementation. + if (ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface()) { + if (auto *IMD = IDecl->lookupMethod(ObjCMethod->getSelector(), + ObjCMethod->isInstanceMethod())) { + mergeInterfaceMethodToImpl(*this, ObjCMethod, IMD); + + // Warn about defining -dealloc in a category. + if (isa<ObjCCategoryImplDecl>(ImpDecl) && IMD->isOverriding() && + ObjCMethod->getSelector().getMethodFamily() == OMF_dealloc) { + Diag(ObjCMethod->getLocation(), diag::warn_dealloc_in_category) + << ObjCMethod->getDeclName(); + } + } } } else { cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod); diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 51d6ace..f3bcf76 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -1041,6 +1041,7 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::CXXReinterpretCastExprClass: case Expr::CXXStdInitializerListExprClass: case Expr::DesignatedInitExprClass: + case Expr::DesignatedInitUpdateExprClass: case Expr::ExprWithCleanupsClass: case Expr::ExtVectorElementExprClass: case Expr::InitListExprClass: @@ -1135,6 +1136,7 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::ImaginaryLiteralClass: case Expr::ImplicitValueInitExprClass: case Expr::IntegerLiteralClass: + case Expr::NoInitExprClass: case Expr::ObjCEncodeExprClass: case Expr::ObjCStringLiteralClass: case Expr::ObjCBoolLiteralExprClass: diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 7e305ff..6c839f3 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -20,7 +20,6 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" -#include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/RecursiveASTVisitor.h" @@ -3291,10 +3290,10 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // We may not have been able to figure out what this member pointer resolved // to up until this exact point. Attempt to lock-in it's inheritance model. - QualType FromType = From->getType(); - if (FromType->isMemberPointerType()) - if (Context.getTargetInfo().getCXXABI().isMicrosoft()) - RequireCompleteType(From->getExprLoc(), FromType, 0); + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { + RequireCompleteType(From->getExprLoc(), From->getType(), 0); + RequireCompleteType(From->getExprLoc(), ToType, 0); + } From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK) .get(); diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 63b7485..9947fad 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -1135,49 +1135,154 @@ ObjCMethodDecl *Sema::tryCaptureObjCSelf(SourceLocation Loc) { } static QualType stripObjCInstanceType(ASTContext &Context, QualType T) { + QualType origType = T; + if (auto nullability = AttributedType::stripOuterNullability(T)) { + if (T == Context.getObjCInstanceType()) { + return Context.getAttributedType( + AttributedType::getNullabilityAttrKind(*nullability), + Context.getObjCIdType(), + Context.getObjCIdType()); + } + + return origType; + } + if (T == Context.getObjCInstanceType()) return Context.getObjCIdType(); - return T; + return origType; } -QualType Sema::getMessageSendResultType(QualType ReceiverType, - ObjCMethodDecl *Method, - bool isClassMessage, bool isSuperMessage) { +/// Determine the result type of a message send based on the receiver type, +/// method, and the kind of message send. +/// +/// This is the "base" result type, which will still need to be adjusted +/// to account for nullability. +static QualType getBaseMessageSendResultType(Sema &S, + QualType ReceiverType, + ObjCMethodDecl *Method, + bool isClassMessage, + bool isSuperMessage) { assert(Method && "Must have a method"); if (!Method->hasRelatedResultType()) return Method->getSendResultType(); - + + ASTContext &Context = S.Context; + + // Local function that transfers the nullability of the method's + // result type to the returned result. + auto transferNullability = [&](QualType type) -> QualType { + // If the method's result type has nullability, extract it. + if (auto nullability = Method->getSendResultType()->getNullability(Context)){ + // Strip off any outer nullability sugar from the provided type. + (void)AttributedType::stripOuterNullability(type); + + // Form a new attributed type using the method result type's nullability. + return Context.getAttributedType( + AttributedType::getNullabilityAttrKind(*nullability), + type, + type); + } + + return type; + }; + // If a method has a related return type: // - if the method found is an instance method, but the message send // was a class message send, T is the declared return type of the method // found if (Method->isInstanceMethod() && isClassMessage) return stripObjCInstanceType(Context, Method->getSendResultType()); - - // - if the receiver is super, T is a pointer to the class of the + + // - if the receiver is super, T is a pointer to the class of the // enclosing method definition if (isSuperMessage) { - if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) - if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface()) - return Context.getObjCObjectPointerType( - Context.getObjCInterfaceType(Class)); + if (ObjCMethodDecl *CurMethod = S.getCurMethodDecl()) + if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface()) { + return transferNullability( + Context.getObjCObjectPointerType( + Context.getObjCInterfaceType(Class))); + } } - + // - if the receiver is the name of a class U, T is a pointer to U if (ReceiverType->getAs<ObjCInterfaceType>() || ReceiverType->isObjCQualifiedInterfaceType()) - return Context.getObjCObjectPointerType(ReceiverType); - // - if the receiver is of type Class or qualified Class type, + return transferNullability(Context.getObjCObjectPointerType(ReceiverType)); + // - if the receiver is of type Class or qualified Class type, // T is the declared return type of the method. if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) return stripObjCInstanceType(Context, Method->getSendResultType()); - + // - if the receiver is id, qualified id, Class, or qualified Class, T // is the receiver type, otherwise // - T is the type of the receiver expression. - return ReceiverType; + return transferNullability(ReceiverType); +} + +QualType Sema::getMessageSendResultType(QualType ReceiverType, + ObjCMethodDecl *Method, + bool isClassMessage, + bool isSuperMessage) { + // Produce the result type. + QualType resultType = getBaseMessageSendResultType(*this, ReceiverType, + Method, + isClassMessage, + isSuperMessage); + + // If this is a class message, ignore the nullability of the receiver. + if (isClassMessage) + return resultType; + + // Map the nullability of the result into a table index. + unsigned receiverNullabilityIdx = 0; + if (auto nullability = ReceiverType->getNullability(Context)) + receiverNullabilityIdx = 1 + static_cast<unsigned>(*nullability); + + unsigned resultNullabilityIdx = 0; + if (auto nullability = resultType->getNullability(Context)) + resultNullabilityIdx = 1 + static_cast<unsigned>(*nullability); + + // The table of nullability mappings, indexed by the receiver's nullability + // and then the result type's nullability. + static const uint8_t None = 0; + static const uint8_t NonNull = 1; + static const uint8_t Nullable = 2; + static const uint8_t Unspecified = 3; + static const uint8_t nullabilityMap[4][4] = { + // None NonNull Nullable Unspecified + /* None */ { None, None, Nullable, None }, + /* NonNull */ { None, NonNull, Nullable, Unspecified }, + /* Nullable */ { Nullable, Nullable, Nullable, Nullable }, + /* Unspecified */ { None, Unspecified, Nullable, Unspecified } + }; + + unsigned newResultNullabilityIdx + = nullabilityMap[receiverNullabilityIdx][resultNullabilityIdx]; + if (newResultNullabilityIdx == resultNullabilityIdx) + return resultType; + + // Strip off the existing nullability. This removes as little type sugar as + // possible. + do { + if (auto attributed = dyn_cast<AttributedType>(resultType.getTypePtr())) { + resultType = attributed->getModifiedType(); + } else { + resultType = resultType.getDesugaredType(Context); + } + } while (resultType->getNullability(Context)); + + // Add nullability back if needed. + if (newResultNullabilityIdx > 0) { + auto newNullability + = static_cast<NullabilityKind>(newResultNullabilityIdx-1); + return Context.getAttributedType( + AttributedType::getNullabilityAttrKind(newNullability), + resultType, resultType); + } + + return resultType; } /// Look for an ObjC method whose result type exactly matches the given type. diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 610e0a9..821d7f6 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -306,7 +306,8 @@ class InitListChecker { QualType CurrentObjectType, InitListExpr *StructuredList, unsigned StructuredIndex, - SourceRange InitRange); + SourceRange InitRange, + bool IsFullyOverwritten = false); void UpdateStructuredListElement(InitListExpr *StructuredList, unsigned &StructuredIndex, Expr *expr); @@ -317,11 +318,33 @@ class InitListChecker { SourceLocation Loc, const InitializedEntity &Entity, bool VerifyOnly); + + // Explanation on the "FillWithNoInit" mode: + // + // Assume we have the following definitions (Case#1): + // struct P { char x[6][6]; } xp = { .x[1] = "bar" }; + // struct PP { struct P lp; } l = { .lp = xp, .lp.x[1][2] = 'f' }; + // + // l.lp.x[1][0..1] should not be filled with implicit initializers because the + // "base" initializer "xp" will provide values for them; l.lp.x[1] will be "baf". + // + // But if we have (Case#2): + // struct PP l = { .lp = xp, .lp.x[1] = { [2] = 'f' } }; + // + // l.lp.x[1][0..1] are implicitly initialized and do not use values from the + // "base" initializer; l.lp.x[1] will be "\0\0f\0\0\0". + // + // To distinguish Case#1 from Case#2, and also to avoid leaving many "holes" + // in the InitListExpr, the "holes" in Case#1 are filled not with empty + // initializers but with special "NoInitExpr" place holders, which tells the + // CodeGen not to generate any initializers for these parts. void FillInEmptyInitForField(unsigned Init, FieldDecl *Field, const InitializedEntity &ParentEntity, - InitListExpr *ILE, bool &RequiresSecondPass); + InitListExpr *ILE, bool &RequiresSecondPass, + bool FillWithNoInit = false); void FillInEmptyInitializations(const InitializedEntity &Entity, - InitListExpr *ILE, bool &RequiresSecondPass); + InitListExpr *ILE, bool &RequiresSecondPass, + bool FillWithNoInit = false); bool CheckFlexibleArrayInit(const InitializedEntity &Entity, Expr *InitExpr, FieldDecl *Field, bool TopLevelObject); @@ -455,12 +478,26 @@ void InitListChecker::CheckEmptyInitializable(const InitializedEntity &Entity, void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, const InitializedEntity &ParentEntity, InitListExpr *ILE, - bool &RequiresSecondPass) { + bool &RequiresSecondPass, + bool FillWithNoInit) { SourceLocation Loc = ILE->getLocEnd(); unsigned NumInits = ILE->getNumInits(); InitializedEntity MemberEntity = InitializedEntity::InitializeMember(Field, &ParentEntity); + + if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) + if (!RType->getDecl()->isUnion()) + assert(Init < NumInits && "This ILE should have been expanded"); + if (Init >= NumInits || !ILE->getInit(Init)) { + if (FillWithNoInit) { + Expr *Filler = new (SemaRef.Context) NoInitExpr(Field->getType()); + if (Init < NumInits) + ILE->setInit(Init, Filler); + else + ILE->updateInit(SemaRef.Context, Init, Filler); + return; + } // C++1y [dcl.init.aggr]p7: // If there are fewer initializer-clauses in the list than there are // members in the aggregate, then each member not explicitly initialized @@ -516,7 +553,11 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, } else if (InitListExpr *InnerILE = dyn_cast<InitListExpr>(ILE->getInit(Init))) FillInEmptyInitializations(MemberEntity, InnerILE, - RequiresSecondPass); + RequiresSecondPass, FillWithNoInit); + else if (DesignatedInitUpdateExpr *InnerDIUE + = dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init))) + FillInEmptyInitializations(MemberEntity, InnerDIUE->getUpdater(), + RequiresSecondPass, /*FillWithNoInit =*/ true); } /// Recursively replaces NULL values within the given initializer list @@ -525,7 +566,8 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, void InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, InitListExpr *ILE, - bool &RequiresSecondPass) { + bool &RequiresSecondPass, + bool FillWithNoInit) { assert((ILE->getType() != SemaRef.Context.VoidTy) && "Should not have void type"); @@ -533,16 +575,27 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, const RecordDecl *RDecl = RType->getDecl(); if (RDecl->isUnion() && ILE->getInitializedFieldInUnion()) FillInEmptyInitForField(0, ILE->getInitializedFieldInUnion(), - Entity, ILE, RequiresSecondPass); + Entity, ILE, RequiresSecondPass, FillWithNoInit); else if (RDecl->isUnion() && isa<CXXRecordDecl>(RDecl) && cast<CXXRecordDecl>(RDecl)->hasInClassInitializer()) { for (auto *Field : RDecl->fields()) { if (Field->hasInClassInitializer()) { - FillInEmptyInitForField(0, Field, Entity, ILE, RequiresSecondPass); + FillInEmptyInitForField(0, Field, Entity, ILE, RequiresSecondPass, + FillWithNoInit); break; } } } else { + // The fields beyond ILE->getNumInits() are default initialized, so in + // order to leave them uninitialized, the ILE is expanded and the extra + // fields are then filled with NoInitExpr. + unsigned NumFields = 0; + for (auto *Field : RDecl->fields()) + if (!Field->isUnnamedBitfield()) + ++NumFields; + if (ILE->getNumInits() < NumFields) + ILE->resizeInits(SemaRef.Context, NumFields); + unsigned Init = 0; for (auto *Field : RDecl->fields()) { if (Field->isUnnamedBitfield()) @@ -551,7 +604,8 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, if (hadError) return; - FillInEmptyInitForField(Init, Field, Entity, ILE, RequiresSecondPass); + FillInEmptyInitForField(Init, Field, Entity, ILE, RequiresSecondPass, + FillWithNoInit); if (hadError) return; @@ -594,13 +648,23 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, ElementEntity.setElementIndex(Init); Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) : nullptr); - if (!InitExpr && !ILE->hasArrayFiller()) { - ExprResult ElementInit = PerformEmptyInit(SemaRef, ILE->getLocEnd(), - ElementEntity, - /*VerifyOnly*/false); - if (ElementInit.isInvalid()) { - hadError = true; - return; + if (!InitExpr && Init < NumInits && ILE->hasArrayFiller()) + ILE->setInit(Init, ILE->getArrayFiller()); + else if (!InitExpr && !ILE->hasArrayFiller()) { + Expr *Filler = nullptr; + + if (FillWithNoInit) + Filler = new (SemaRef.Context) NoInitExpr(ElementType); + else { + ExprResult ElementInit = PerformEmptyInit(SemaRef, ILE->getLocEnd(), + ElementEntity, + /*VerifyOnly*/false); + if (ElementInit.isInvalid()) { + hadError = true; + return; + } + + Filler = ElementInit.getAs<Expr>(); } if (hadError) { @@ -609,29 +673,34 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, // For arrays, just set the expression used for value-initialization // of the "holes" in the array. if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement) - ILE->setArrayFiller(ElementInit.getAs<Expr>()); + ILE->setArrayFiller(Filler); else - ILE->setInit(Init, ElementInit.getAs<Expr>()); + ILE->setInit(Init, Filler); } else { // For arrays, just set the expression used for value-initialization // of the rest of elements and exit. if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement) { - ILE->setArrayFiller(ElementInit.getAs<Expr>()); + ILE->setArrayFiller(Filler); return; } - if (!isa<ImplicitValueInitExpr>(ElementInit.get())) { + if (!isa<ImplicitValueInitExpr>(Filler) && !isa<NoInitExpr>(Filler)) { // Empty initialization requires a constructor call, so // extend the initializer list to include the constructor // call and make a note that we'll need to take another pass // through the initializer list. - ILE->updateInit(SemaRef.Context, Init, ElementInit.getAs<Expr>()); + ILE->updateInit(SemaRef.Context, Init, Filler); RequiresSecondPass = true; } } } else if (InitListExpr *InnerILE = dyn_cast_or_null<InitListExpr>(InitExpr)) - FillInEmptyInitializations(ElementEntity, InnerILE, RequiresSecondPass); + FillInEmptyInitializations(ElementEntity, InnerILE, RequiresSecondPass, + FillWithNoInit); + else if (DesignatedInitUpdateExpr *InnerDIUE + = dyn_cast_or_null<DesignatedInitUpdateExpr>(InitExpr)) + FillInEmptyInitializations(ElementEntity, InnerDIUE->getUpdater(), + RequiresSecondPass, /*FillWithNoInit =*/ true); } } @@ -966,13 +1035,26 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, StructuredList, StructuredIndex); if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) { - if (!SemaRef.getLangOpts().CPlusPlus) { + if (SubInitList->getNumInits() == 1 && + IsStringInit(SubInitList->getInit(0), ElemType, SemaRef.Context) == + SIF_None) { + expr = SubInitList->getInit(0); + } else if (!SemaRef.getLangOpts().CPlusPlus) { InitListExpr *InnerStructuredList = getStructuredSubobjectInit(IList, Index, ElemType, StructuredList, StructuredIndex, - SubInitList->getSourceRange()); + SubInitList->getSourceRange(), true); CheckExplicitInitList(Entity, SubInitList, ElemType, InnerStructuredList); + + if (!hadError && !VerifyOnly) { + bool RequiresSecondPass = false; + FillInEmptyInitializations(Entity, InnerStructuredList, + RequiresSecondPass); + if (RequiresSecondPass && !hadError) + FillInEmptyInitializations(Entity, InnerStructuredList, + RequiresSecondPass); + } ++StructuredIndex; ++Index; return; @@ -1913,11 +1995,66 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Determine the structural initializer list that corresponds to the // current subobject. - StructuredList = IsFirstDesignator? SyntacticToSemantic.lookup(IList) - : getStructuredSubobjectInit(IList, Index, CurrentObjectType, - StructuredList, StructuredIndex, - SourceRange(D->getLocStart(), - DIE->getLocEnd())); + if (IsFirstDesignator) + StructuredList = SyntacticToSemantic.lookup(IList); + else { + Expr *ExistingInit = StructuredIndex < StructuredList->getNumInits() ? + StructuredList->getInit(StructuredIndex) : nullptr; + if (!ExistingInit && StructuredList->hasArrayFiller()) + ExistingInit = StructuredList->getArrayFiller(); + + if (!ExistingInit) + StructuredList = + getStructuredSubobjectInit(IList, Index, CurrentObjectType, + StructuredList, StructuredIndex, + SourceRange(D->getLocStart(), + DIE->getLocEnd())); + else if (InitListExpr *Result = dyn_cast<InitListExpr>(ExistingInit)) + StructuredList = Result; + else { + if (DesignatedInitUpdateExpr *E = + dyn_cast<DesignatedInitUpdateExpr>(ExistingInit)) + StructuredList = E->getUpdater(); + else { + DesignatedInitUpdateExpr *DIUE = + new (SemaRef.Context) DesignatedInitUpdateExpr(SemaRef.Context, + D->getLocStart(), ExistingInit, + DIE->getLocEnd()); + StructuredList->updateInit(SemaRef.Context, StructuredIndex, DIUE); + StructuredList = DIUE->getUpdater(); + } + + // We need to check on source range validity because the previous + // initializer does not have to be an explicit initializer. e.g., + // + // struct P { int a, b; }; + // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 }; + // + // There is an overwrite taking place because the first braced initializer + // list "{ .a = 2 }" already provides value for .p.b (which is zero). + if (ExistingInit->getSourceRange().isValid()) { + // We are creating an initializer list that initializes the + // subobjects of the current object, but there was already an + // initialization that completely initialized the current + // subobject, e.g., by a compound literal: + // + // struct X { int a, b; }; + // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 }; + // + // Here, xs[0].a == 0 and xs[0].b == 3, since the second, + // designated initializer re-initializes the whole + // subobject [0], overwriting previous initializers. + SemaRef.Diag(D->getLocStart(), + diag::warn_subobject_initializer_overrides) + << SourceRange(D->getLocStart(), DIE->getLocEnd()); + + SemaRef.Diag(ExistingInit->getLocStart(), + diag::note_previous_initializer) + << /*FIXME:has side effects=*/0 + << ExistingInit->getSourceRange(); + } + } + } assert(StructuredList && "Expected a structured initializer list"); } @@ -2367,7 +2504,8 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, QualType CurrentObjectType, InitListExpr *StructuredList, unsigned StructuredIndex, - SourceRange InitRange) { + SourceRange InitRange, + bool IsFullyOverwritten) { if (VerifyOnly) return nullptr; // No structured list in verification-only mode. Expr *ExistingInit = nullptr; @@ -2377,7 +2515,16 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, ExistingInit = StructuredList->getInit(StructuredIndex); if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit)) - return Result; + // There might have already been initializers for subobjects of the current + // object, but a subsequent initializer list will overwrite the entirety + // of the current object. (See DR 253 and C99 6.7.8p21). e.g., + // + // struct P { char x[6]; }; + // struct P l = { .x[2] = 'x', .x = { [0] = 'f' } }; + // + // The first designated initializer is ignored, and l.x is just "f". + if (!IsFullyOverwritten) + return Result; if (ExistingInit) { // We are creating an initializer list that initializes the @@ -2469,13 +2616,22 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList, if (Expr *PrevInit = StructuredList->updateInit(SemaRef.Context, StructuredIndex, expr)) { // This initializer overwrites a previous initializer. Warn. - SemaRef.Diag(expr->getLocStart(), - diag::warn_initializer_overrides) - << expr->getSourceRange(); - SemaRef.Diag(PrevInit->getLocStart(), - diag::note_previous_initializer) - << /*FIXME:has side effects=*/0 - << PrevInit->getSourceRange(); + // We need to check on source range validity because the previous + // initializer does not have to be an explicit initializer. + // struct P { int a, b; }; + // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 }; + // There is an overwrite taking place because the first braced initializer + // list "{ .a = 2 }' already provides value for .p.b (which is zero). + if (PrevInit->getSourceRange().isValid()) { + SemaRef.Diag(expr->getLocStart(), + diag::warn_initializer_overrides) + << expr->getSourceRange(); + + SemaRef.Diag(PrevInit->getLocStart(), + diag::note_previous_initializer) + << /*FIXME:has side effects=*/0 + << PrevInit->getSourceRange(); + } } ++StructuredIndex; diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index d0a55b5..3fd1f21 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1233,6 +1233,12 @@ void Sema::makeMergedDefinitionVisible(NamedDecl *ND, SourceLocation Loc) { else // We're not building a module; just make the definition visible. ND->setHidden(false); + + // If ND is a template declaration, make the template parameters + // visible too. They're not (necessarily) within a mergeable DeclContext. + if (auto *TD = dyn_cast<TemplateDecl>(ND)) + for (auto *Param : *TD->getTemplateParameters()) + makeMergedDefinitionVisible(Param, Loc); } /// \brief Find the module in which the given declaration was defined. @@ -1282,6 +1288,41 @@ bool Sema::hasVisibleMergedDefinition(NamedDecl *Def) { return false; } +template<typename ParmDecl> +static bool +hasVisibleDefaultArgument(Sema &S, const ParmDecl *D, + llvm::SmallVectorImpl<Module *> *Modules) { + if (!D->hasDefaultArgument()) + return false; + + while (D) { + auto &DefaultArg = D->getDefaultArgStorage(); + if (!DefaultArg.isInherited() && S.isVisible(D)) + return true; + + if (!DefaultArg.isInherited() && Modules) { + auto *NonConstD = const_cast<ParmDecl*>(D); + Modules->push_back(S.getOwningModule(NonConstD)); + const auto &Merged = S.Context.getModulesWithMergedDefinition(NonConstD); + Modules->insert(Modules->end(), Merged.begin(), Merged.end()); + } + + // If there was a previous default argument, maybe its parameter is visible. + D = DefaultArg.getInheritedFrom(); + } + return false; +} + +bool Sema::hasVisibleDefaultArgument(const NamedDecl *D, + llvm::SmallVectorImpl<Module *> *Modules) { + if (auto *P = dyn_cast<TemplateTypeParmDecl>(D)) + return ::hasVisibleDefaultArgument(*this, P, Modules); + if (auto *P = dyn_cast<NonTypeTemplateParmDecl>(D)) + return ::hasVisibleDefaultArgument(*this, P, Modules); + return ::hasVisibleDefaultArgument(*this, cast<TemplateTemplateParmDecl>(D), + Modules); +} + /// \brief Determine whether a declaration is visible to name lookup. /// /// This routine determines whether the declaration D is visible in the current @@ -3006,6 +3047,9 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) continue; + if (!isVisible(D) && !(D = findAcceptableDecl(*this, D))) + continue; + Result.insert(D); } } @@ -4632,6 +4676,76 @@ static NamedDecl *getDefinitionToImport(NamedDecl *D) { return nullptr; } +void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, + bool NeedDefinition, bool Recover) { + assert(!isVisible(Decl) && "missing import for non-hidden decl?"); + + // Suggest importing a module providing the definition of this entity, if + // possible. + NamedDecl *Def = getDefinitionToImport(Decl); + if (!Def) + Def = Decl; + + // FIXME: Add a Fix-It that imports the corresponding module or includes + // the header. + Module *Owner = getOwningModule(Decl); + assert(Owner && "definition of hidden declaration is not in a module"); + + llvm::SmallVector<Module*, 8> OwningModules; + OwningModules.push_back(Owner); + auto Merged = Context.getModulesWithMergedDefinition(Decl); + OwningModules.insert(OwningModules.end(), Merged.begin(), Merged.end()); + + diagnoseMissingImport(Loc, Decl, Decl->getLocation(), OwningModules, + NeedDefinition ? MissingImportKind::Definition + : MissingImportKind::Declaration, + Recover); +} + +void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, + SourceLocation DeclLoc, + ArrayRef<Module *> Modules, + MissingImportKind MIK, bool Recover) { + assert(!Modules.empty()); + + if (Modules.size() > 1) { + std::string ModuleList; + unsigned N = 0; + for (Module *M : Modules) { + ModuleList += "\n "; + if (++N == 5 && N != Modules.size()) { + ModuleList += "[...]"; + break; + } + ModuleList += M->getFullModuleName(); + } + + Diag(UseLoc, diag::err_module_unimported_use_multiple) + << (int)MIK << Decl << ModuleList; + } else { + Diag(UseLoc, diag::err_module_unimported_use) + << (int)MIK << Decl << Modules[0]->getFullModuleName(); + } + + unsigned DiagID; + switch (MIK) { + case MissingImportKind::Declaration: + DiagID = diag::note_previous_declaration; + break; + case MissingImportKind::Definition: + DiagID = diag::note_previous_definition; + break; + case MissingImportKind::DefaultArgument: + DiagID = diag::note_default_argument_declared_here; + break; + } + Diag(DeclLoc, DiagID); + + // Try to recover by implicitly importing this module. + if (Recover) + createImplicitModuleImportForErrorRecovery(UseLoc, Modules[0]); +} + /// \brief Diagnose a successfully-corrected typo. Separated from the correction /// itself to allow external validation of the result, etc. /// @@ -4658,23 +4772,8 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction, NamedDecl *Decl = Correction.getCorrectionDecl(); assert(Decl && "import required but no declaration to import"); - // Suggest importing a module providing the definition of this entity, if - // possible. - NamedDecl *Def = getDefinitionToImport(Decl); - if (!Def) - Def = Decl; - Module *Owner = getOwningModule(Def); - assert(Owner && "definition of hidden declaration is not in a module"); - - Diag(Correction.getCorrectionRange().getBegin(), - diag::err_module_private_declaration) - << Def << Owner->getFullModuleName(); - Diag(Def->getLocation(), diag::note_previous_declaration); - - // Recover by implicitly importing this module. - if (ErrorRecovery) - createImplicitModuleImportForErrorRecovery( - Correction.getCorrectionRange().getBegin(), Owner); + diagnoseMissingImport(Correction.getCorrectionRange().getBegin(), Decl, + /*NeedDefinition*/ false, ErrorRecovery); return; } diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 5e7b4b8..87fb5b6 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -103,15 +103,6 @@ static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) { << propertyLifetime; } -static unsigned deduceWeakPropertyFromType(Sema &S, QualType T) { - if ((S.getLangOpts().getGC() != LangOptions::NonGC && - T.isObjCGCWeak()) || - (S.getLangOpts().ObjCAutoRefCount && - T.getObjCLifetime() == Qualifiers::OCL_Weak)) - return ObjCDeclSpec::DQ_PR_weak; - return 0; -} - /// \brief Check this Objective-C property against a property declared in the /// given protocol. static void @@ -146,10 +137,10 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC) { unsigned Attributes = ODS.getPropertyAttributes(); + FD.D.setObjCWeakProperty((Attributes & ObjCDeclSpec::DQ_PR_weak) != 0); TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S); QualType T = TSI->getType(); - Attributes |= deduceWeakPropertyFromType(*this, T); - + Attributes |= deduceWeakPropertyFromType(T); bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) || // default is readwrite! !(Attributes & ObjCDeclSpec::DQ_PR_readonly)); @@ -173,7 +164,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, isAssign, isReadWrite, Attributes, ODS.getPropertyAttributes(), - isOverridingProperty, TSI, + isOverridingProperty, T, TSI, MethodImplKind); if (!Res) return nullptr; @@ -184,7 +175,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, Attributes, ODS.getPropertyAttributes(), - TSI, MethodImplKind); + T, TSI, MethodImplKind); if (lexicalDC) Res->setLexicalDeclContext(lexicalDC); } @@ -322,7 +313,8 @@ Sema::HandlePropertyInClassExtension(Scope *S, const unsigned Attributes, const unsigned AttributesAsWritten, bool *isOverridingProperty, - TypeSourceInfo *T, + QualType T, + TypeSourceInfo *TSI, tok::ObjCKeywordKind MethodImplKind) { ObjCCategoryDecl *CDecl = cast<ObjCCategoryDecl>(CurContext); // Diagnose if this property is already in continuation class. @@ -348,7 +340,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, // FIXME. We should really be using CreatePropertyDecl for this. ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), - PropertyId, AtLoc, LParenLoc, T); + PropertyId, AtLoc, LParenLoc, T, TSI); PDecl->setPropertyAttributesAsWritten( makePropertyAttributesAsWritten(AttributesAsWritten)); if (Attributes & ObjCDeclSpec::DQ_PR_readonly) @@ -359,6 +351,11 @@ Sema::HandlePropertyInClassExtension(Scope *S, PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); if (Attributes & ObjCDeclSpec::DQ_PR_atomic) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic); + if (Attributes & ObjCDeclSpec::DQ_PR_nullability) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nullability); + if (Attributes & ObjCDeclSpec::DQ_PR_null_resettable) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_null_resettable); + // Set setter/getter selector name. Needed later. PDecl->setGetterName(GetterSel); PDecl->setSetterName(SetterSel); @@ -383,7 +380,8 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCPropertyDecl *PrimaryPDecl = CreatePropertyDecl(S, CCPrimary, AtLoc, LParenLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, - Attributes,AttributesAsWritten, T, MethodImplKind, DC); + Attributes,AttributesAsWritten, T, TSI, MethodImplKind, + DC); // A case of continuation class adding a new property in the class. This // is not what it was meant for. However, gcc supports it and so should we. @@ -427,7 +425,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { PIkind &= ~ObjCPropertyDecl::OBJC_PR_readonly; PIkind |= ObjCPropertyDecl::OBJC_PR_readwrite; - PIkind |= deduceWeakPropertyFromType(*this, PIDecl->getType()); + PIkind |= deduceWeakPropertyFromType(PIDecl->getType()); unsigned ClassExtensionMemoryModel = getOwnershipRule(Attributes); unsigned PrimaryClassMemoryModel = getOwnershipRule(PIkind); if (PrimaryClassMemoryModel && ClassExtensionMemoryModel && @@ -531,11 +529,11 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, const bool isReadWrite, const unsigned Attributes, const unsigned AttributesAsWritten, + QualType T, TypeSourceInfo *TInfo, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC){ IdentifierInfo *PropertyId = FD.D.getIdentifier(); - QualType T = TInfo->getType(); // Issue a warning if property is 'assign' as default and its object, which is // gc'able conforms to NSCopying protocol @@ -564,7 +562,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, DeclContext *DC = cast<DeclContext>(CDecl); ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), - PropertyId, AtLoc, LParenLoc, TInfo); + PropertyId, AtLoc, + LParenLoc, T, TInfo); if (ObjCPropertyDecl *prevDecl = ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) { @@ -639,6 +638,12 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, else if (MethodImplKind == tok::objc_optional) PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional); + if (Attributes & ObjCDeclSpec::DQ_PR_nullability) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nullability); + + if (Attributes & ObjCDeclSpec::DQ_PR_null_resettable) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_null_resettable); + return PDecl; } @@ -1753,6 +1758,33 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, } } +void Sema::diagnoseNullResettableSynthesizedSetters(ObjCImplDecl *impDecl) { + for (const auto *propertyImpl : impDecl->property_impls()) { + const auto *property = propertyImpl->getPropertyDecl(); + + // Warn about null_resettable properties with synthesized setters, + // because the setter won't properly handle nil. + if (propertyImpl->getPropertyImplementation() + == ObjCPropertyImplDecl::Synthesize && + (property->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_null_resettable) && + property->getGetterMethodDecl() && + property->getSetterMethodDecl()) { + auto *getterMethod = property->getGetterMethodDecl(); + auto *setterMethod = property->getSetterMethodDecl(); + if (!impDecl->getInstanceMethod(setterMethod->getSelector()) && + !impDecl->getInstanceMethod(getterMethod->getSelector())) { + SourceLocation loc = propertyImpl->getLocation(); + if (loc.isInvalid()) + loc = impDecl->getLocStart(); + + Diag(loc, diag::warn_null_resettable_setter) + << setterMethod->getSelector() << property->getDeclName(); + } + } + } +} + void Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl) { @@ -1988,9 +2020,21 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, redeclaredProperty->getLocation() : property->getLocation(); + // If the property is null_resettable, the getter returns nonnull. + QualType resultTy = property->getType(); + if (property->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_null_resettable) { + QualType modifiedTy = resultTy; + if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)){ + if (*nullability == NullabilityKind::Unspecified) + resultTy = Context.getAttributedType(AttributedType::attr_nonnull, + modifiedTy, modifiedTy); + } + } + GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc, property->getGetterName(), - property->getType(), nullptr, CD, + resultTy, nullptr, CD, /*isInstance=*/true, /*isVariadic=*/false, /*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, @@ -2051,12 +2095,25 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCMethodDecl::Optional : ObjCMethodDecl::Required); + // If the property is null_resettable, the setter accepts a + // nullable value. + QualType paramTy = property->getType().getUnqualifiedType(); + if (property->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_null_resettable) { + QualType modifiedTy = paramTy; + if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)){ + if (*nullability == NullabilityKind::Unspecified) + paramTy = Context.getAttributedType(AttributedType::attr_nullable, + modifiedTy, modifiedTy); + } + } + // Invent the arguments for the setter. We don't bother making a // nice name for the argument. ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod, Loc, Loc, property->getIdentifier(), - property->getType().getUnqualifiedType(), + paramTy, /*TInfo=*/nullptr, SC_None, nullptr); @@ -2228,6 +2285,22 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, Attributes &= ~ObjCDeclSpec::DQ_PR_weak; } + if (Attributes & ObjCDeclSpec::DQ_PR_weak) { + // 'weak' and 'nonnull' are mutually exclusive. + if (auto nullability = PropertyTy->getNullability(Context)) { + if (*nullability == NullabilityKind::NonNull) + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "nonnull" << "weak"; + } else { + PropertyTy = + Context.getAttributedType( + AttributedType::getNullabilityAttrKind(NullabilityKind::Nullable), + PropertyTy, PropertyTy); + TypeSourceInfo *TSInfo = PropertyDecl->getTypeSourceInfo(); + PropertyDecl->setType(PropertyTy, TSInfo); + } + } + if ((Attributes & ObjCDeclSpec::DQ_PR_atomic) && (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index cfe8db3..e609fcf 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -1270,6 +1270,14 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Params); break; } + case OMPD_taskgroup: { + Sema::CapturedParamNameType Params[] = { + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); + break; + } case OMPD_threadprivate: case OMPD_taskyield: case OMPD_barrier: @@ -1335,6 +1343,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel | taskyield | * | // | parallel | barrier | * | // | parallel | taskwait | * | + // | parallel | taskgroup | * | // | parallel | flush | * | // | parallel | ordered | + | // | parallel | atomic | * | @@ -1357,6 +1366,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | for | taskyield | * | // | for | barrier | + | // | for | taskwait | * | + // | for | taskgroup | * | // | for | flush | * | // | for | ordered | * (if construct is ordered) | // | for | atomic | * | @@ -1379,6 +1389,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | master | taskyield | * | // | master | barrier | + | // | master | taskwait | * | + // | master | taskgroup | * | // | master | flush | * | // | master | ordered | + | // | master | atomic | * | @@ -1401,6 +1412,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | critical | taskyield | * | // | critical | barrier | + | // | critical | taskwait | * | + // | critical | taskgroup | * | // | critical | ordered | + | // | critical | atomic | * | // | critical | target | * | @@ -1422,6 +1434,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | simd | taskyield | | // | simd | barrier | | // | simd | taskwait | | + // | simd | taskgroup | | // | simd | flush | | // | simd | ordered | | // | simd | atomic | | @@ -1444,6 +1457,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | for simd | taskyield | | // | for simd | barrier | | // | for simd | taskwait | | + // | for simd | taskgroup | | // | for simd | flush | | // | for simd | ordered | | // | for simd | atomic | | @@ -1466,6 +1480,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel for simd| taskyield | | // | parallel for simd| barrier | | // | parallel for simd| taskwait | | + // | parallel for simd| taskgroup | | // | parallel for simd| flush | | // | parallel for simd| ordered | | // | parallel for simd| atomic | | @@ -1488,6 +1503,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | sections | taskyield | * | // | sections | barrier | + | // | sections | taskwait | * | + // | sections | taskgroup | * | // | sections | flush | * | // | sections | ordered | + | // | sections | atomic | * | @@ -1510,6 +1526,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | section | taskyield | * | // | section | barrier | + | // | section | taskwait | * | + // | section | taskgroup | * | // | section | flush | * | // | section | ordered | + | // | section | atomic | * | @@ -1532,6 +1549,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | single | taskyield | * | // | single | barrier | + | // | single | taskwait | * | + // | single | taskgroup | * | // | single | flush | * | // | single | ordered | + | // | single | atomic | * | @@ -1554,6 +1572,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel for | taskyield | * | // | parallel for | barrier | + | // | parallel for | taskwait | * | + // | parallel for | taskgroup | * | // | parallel for | flush | * | // | parallel for | ordered | * (if construct is ordered) | // | parallel for | atomic | * | @@ -1576,6 +1595,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel sections| taskyield | * | // | parallel sections| barrier | + | // | parallel sections| taskwait | * | + // | parallel sections| taskgroup | * | // | parallel sections| flush | * | // | parallel sections| ordered | + | // | parallel sections| atomic | * | @@ -1598,6 +1618,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | task | taskyield | * | // | task | barrier | + | // | task | taskwait | * | + // | task | taskgroup | * | // | task | flush | * | // | task | ordered | + | // | task | atomic | * | @@ -1620,6 +1641,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | ordered | taskyield | * | // | ordered | barrier | + | // | ordered | taskwait | * | + // | ordered | taskgroup | * | // | ordered | flush | * | // | ordered | ordered | + | // | ordered | atomic | * | @@ -1642,6 +1664,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | atomic | taskyield | | // | atomic | barrier | | // | atomic | taskwait | | + // | atomic | taskgroup | | // | atomic | flush | | // | atomic | ordered | | // | atomic | atomic | | @@ -1664,6 +1687,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | target | taskyield | * | // | target | barrier | * | // | target | taskwait | * | + // | target | taskgroup | * | // | target | flush | * | // | target | ordered | * | // | target | atomic | * | @@ -1686,6 +1710,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | teams | taskyield | + | // | teams | barrier | + | // | teams | taskwait | + | + // | teams | taskgroup | + | // | teams | flush | + | // | teams | ordered | + | // | teams | atomic | + | @@ -1936,6 +1961,11 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind, "No associated statement allowed for 'omp taskwait' directive"); Res = ActOnOpenMPTaskwaitDirective(StartLoc, EndLoc); break; + case OMPD_taskgroup: + assert(ClausesWithImplicit.empty() && + "No clauses are allowed for 'omp taskgroup' directive"); + Res = ActOnOpenMPTaskgroupDirective(AStmt, StartLoc, EndLoc); + break; case OMPD_flush: assert(AStmt == nullptr && "No associated statement allowed for 'omp flush' directive"); @@ -2939,9 +2969,6 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, ? SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get()) : SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(), NumIterations.get()); - // Loop condition with 1 iteration separated (IV < LastIteration) - ExprResult SeparatedCond = SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, - IV.get(), LastIteration.get()); // Loop increment (IV = IV + 1) SourceLocation IncLoc; @@ -3071,7 +3098,6 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, Built.CalcLastIteration = CalcLastIteration.get(); Built.PreCond = PreCond.get(); Built.Cond = Cond.get(); - Built.SeparatedCond = SeparatedCond.get(); Built.Init = Init.get(); Built.Inc = Inc.get(); Built.LB = LB.get(); @@ -3161,6 +3187,16 @@ StmtResult Sema::ActOnOpenMPForSimdDirective( assert((CurContext->isDependentContext() || B.builtAll()) && "omp for simd loop exprs were not built"); + if (!CurContext->isDependentContext()) { + // Finalize the clauses that need pre-built expressions for CodeGen. + for (auto C : Clauses) { + if (auto LC = dyn_cast<OMPLinearClause>(C)) + if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), + B.NumIterations, *this, CurScope)) + return StmtError(); + } + } + getCurFunction()->setHasBranchProtectedScope(); return OMPForSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); @@ -3310,6 +3346,16 @@ StmtResult Sema::ActOnOpenMPParallelForSimdDirective( if (NestedLoopCount == 0) return StmtError(); + if (!CurContext->isDependentContext()) { + // Finalize the clauses that need pre-built expressions for CodeGen. + for (auto C : Clauses) { + if (auto LC = dyn_cast<OMPLinearClause>(C)) + if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), + B.NumIterations, *this, CurScope)) + return StmtError(); + } + } + getCurFunction()->setHasBranchProtectedScope(); return OMPParallelForSimdDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); @@ -3382,6 +3428,16 @@ StmtResult Sema::ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc, return OMPTaskwaitDirective::Create(Context, StartLoc, EndLoc); } +StmtResult Sema::ActOnOpenMPTaskgroupDirective(Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + + getCurFunction()->setHasBranchProtectedScope(); + + return OMPTaskgroupDirective::Create(Context, StartLoc, EndLoc, AStmt); +} + StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc, SourceLocation EndLoc) { diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 9d87a10..a0fdcd7 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -10507,7 +10507,8 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc, const CXXScopeSpec &SS, LookupResult &R, OverloadCandidateSet::CandidateSetKind CSK, TemplateArgumentListInfo *ExplicitTemplateArgs, - ArrayRef<Expr *> Args) { + ArrayRef<Expr *> Args, + bool *DoDiagnoseEmptyLookup = nullptr) { if (SemaRef.ActiveTemplateInstantiations.empty() || !SS.isEmpty()) return false; @@ -10524,6 +10525,8 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc, // Don't diagnose names we find in classes; we get much better // diagnostics for these from DiagnoseEmptyLookup. R.clear(); + if (DoDiagnoseEmptyLookup) + *DoDiagnoseEmptyLookup = true; return false; } @@ -10673,15 +10676,16 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(), Sema::LookupOrdinaryName); + bool DoDiagnoseEmptyLookup = EmptyLookup; if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R, OverloadCandidateSet::CSK_Normal, - ExplicitTemplateArgs, Args) && - (!EmptyLookup || - SemaRef.DiagnoseEmptyLookup( - S, SS, R, - MakeValidator(SemaRef, dyn_cast<MemberExpr>(Fn), Args.size(), - ExplicitTemplateArgs != nullptr, AllowTypoCorrection), - ExplicitTemplateArgs, Args))) + ExplicitTemplateArgs, Args, + &DoDiagnoseEmptyLookup) && + (!DoDiagnoseEmptyLookup || SemaRef.DiagnoseEmptyLookup( + S, SS, R, + MakeValidator(SemaRef, dyn_cast<MemberExpr>(Fn), Args.size(), + ExplicitTemplateArgs != nullptr, AllowTypoCorrection), + ExplicitTemplateArgs, Args))) return ExprError(); assert(!R.empty() && "lookup results empty despite recovery"); @@ -10746,26 +10750,29 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn, // functions, including those from argument-dependent lookup. AddOverloadedCallCandidates(ULE, Args, *CandidateSet); - // If we found nothing, try to recover. - // BuildRecoveryCallExpr diagnoses the error itself, so we just bail - // out if it fails. - if (CandidateSet->empty()) { - // In Microsoft mode, if we are inside a template class member function then - // create a type dependent CallExpr. The goal is to postpone name lookup - // to instantiation time to be able to search into type dependent base - // classes. - if (getLangOpts().MSVCCompat && CurContext->isDependentContext() && - (isa<FunctionDecl>(CurContext) || isa<CXXRecordDecl>(CurContext))) { - CallExpr *CE = new (Context) CallExpr(Context, Fn, Args, - Context.DependentTy, VK_RValue, - RParenLoc); + if (getLangOpts().MSVCCompat && + CurContext->isDependentContext() && !isSFINAEContext() && + (isa<FunctionDecl>(CurContext) || isa<CXXRecordDecl>(CurContext))) { + + OverloadCandidateSet::iterator Best; + if (CandidateSet->empty() || + CandidateSet->BestViableFunction(*this, Fn->getLocStart(), Best) == + OR_No_Viable_Function) { + // In Microsoft mode, if we are inside a template class member function then + // create a type dependent CallExpr. The goal is to postpone name lookup + // to instantiation time to be able to search into type dependent base + // classes. + CallExpr *CE = new (Context) CallExpr( + Context, Fn, Args, Context.DependentTy, VK_RValue, RParenLoc); CE->setTypeDependent(true); *Result = CE; return true; } - return false; } + if (CandidateSet->empty()) + return false; + UnbridgedCasts.restore(); return false; } @@ -11253,7 +11260,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, if (Op == OO_Equal) DiagnoseSelfMove(Args[0], Args[1], OpLoc); - checkCall(FnDecl, ArgsArray, 0, isa<CXXMethodDecl>(FnDecl), OpLoc, + checkCall(FnDecl, nullptr, ArgsArray, isa<CXXMethodDecl>(FnDecl), OpLoc, TheCall->getSourceRange(), VariadicDoesNotApply); return MaybeBindToTemporary(TheCall); diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 5c72529..50e4345 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -3432,7 +3432,7 @@ class CatchHandlerType { public: /// Used when creating a CatchHandlerType from a handler type; will determine - /// whether the type is a pointer or reference and will strip off the the top + /// whether the type is a pointer or reference and will strip off the top /// level pointer and cv-qualifiers. CatchHandlerType(QualType Q) : QT(Q), IsPointer(false) { if (QT->isPointerType()) diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp index 19e2c8e..5b71c11 100644 --- a/lib/Sema/SemaStmtAttr.cpp +++ b/lib/Sema/SemaStmtAttr.cpp @@ -105,6 +105,8 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, if (StateLoc && StateLoc->Ident) { if (StateLoc->Ident->isStr("disable")) State = LoopHintAttr::Disable; + else if (StateLoc->Ident->isStr("assume_safety")) + State = LoopHintAttr::AssumeSafety; else State = LoopHintAttr::Enable; } @@ -159,7 +161,7 @@ CheckForIncompatibleAttributes(Sema &S, const LoopHintAttr *PrevAttr; if (Option == LoopHintAttr::Vectorize || Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) { - // Enable|disable hint. For example, vectorize(enable). + // Enable|Disable|AssumeSafety hint. For example, vectorize(enable). PrevAttr = CategoryState.StateAttr; CategoryState.StateAttr = LH; } else { diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 19c0f2a..f4740a5 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -602,7 +602,7 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, return Param; } - Param->setDefaultArgument(DefaultTInfo, false); + Param->setDefaultArgument(DefaultTInfo); } return Param; @@ -723,7 +723,7 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, } Default = DefaultRes.get(); - Param->setDefaultArgument(Default, false); + Param->setDefaultArgument(Default); } return Param; @@ -799,7 +799,7 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, UPPC_DefaultArgument)) return Param; - Param->setDefaultArgument(DefaultArg, false); + Param->setDefaultArgument(Context, DefaultArg); } return Param; @@ -1310,15 +1310,11 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // Merge default arguments for template type parameters. TemplateTypeParmDecl *OldTypeParm = OldParams? cast<TemplateTypeParmDecl>(*OldParam) : nullptr; - // FIXME: There might be a visible declaration of this template parameter. - if (OldTypeParm && !LookupResult::isVisible(*this, OldTypeParm)) - OldTypeParm = nullptr; - if (NewTypeParm->isParameterPack()) { assert(!NewTypeParm->hasDefaultArgument() && "Parameter packs can't have a default argument!"); SawParameterPack = true; - } else if (OldTypeParm && OldTypeParm->hasDefaultArgument() && + } else if (OldTypeParm && hasVisibleDefaultArgument(OldTypeParm) && NewTypeParm->hasDefaultArgument()) { OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc(); NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc(); @@ -1328,8 +1324,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, } else if (OldTypeParm && OldTypeParm->hasDefaultArgument()) { // Merge the default argument from the old declaration to the // new declaration. - NewTypeParm->setDefaultArgument(OldTypeParm->getDefaultArgumentInfo(), - true); + NewTypeParm->setInheritedDefaultArgument(Context, OldTypeParm); PreviousDefaultArgLoc = OldTypeParm->getDefaultArgumentLoc(); } else if (NewTypeParm->hasDefaultArgument()) { SawDefaultArgument = true; @@ -1358,14 +1353,12 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // Merge default arguments for non-type template parameters NonTypeTemplateParmDecl *OldNonTypeParm = OldParams? cast<NonTypeTemplateParmDecl>(*OldParam) : nullptr; - if (OldNonTypeParm && !LookupResult::isVisible(*this, OldNonTypeParm)) - OldNonTypeParm = nullptr; if (NewNonTypeParm->isParameterPack()) { assert(!NewNonTypeParm->hasDefaultArgument() && "Parameter packs can't have a default argument!"); if (!NewNonTypeParm->isPackExpansion()) SawParameterPack = true; - } else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() && + } else if (OldNonTypeParm && hasVisibleDefaultArgument(OldNonTypeParm) && NewNonTypeParm->hasDefaultArgument()) { OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc(); NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc(); @@ -1375,12 +1368,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, } else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument()) { // Merge the default argument from the old declaration to the // new declaration. - // FIXME: We need to create a new kind of "default argument" - // expression that points to a previous non-type template - // parameter. - NewNonTypeParm->setDefaultArgument( - OldNonTypeParm->getDefaultArgument(), - /*Inherited=*/ true); + NewNonTypeParm->setInheritedDefaultArgument(Context, OldNonTypeParm); PreviousDefaultArgLoc = OldNonTypeParm->getDefaultArgumentLoc(); } else if (NewNonTypeParm->hasDefaultArgument()) { SawDefaultArgument = true; @@ -1407,15 +1395,14 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // Merge default arguments for template template parameters TemplateTemplateParmDecl *OldTemplateParm = OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : nullptr; - if (OldTemplateParm && !LookupResult::isVisible(*this, OldTemplateParm)) - OldTemplateParm = nullptr; if (NewTemplateParm->isParameterPack()) { assert(!NewTemplateParm->hasDefaultArgument() && "Parameter packs can't have a default argument!"); if (!NewTemplateParm->isPackExpansion()) SawParameterPack = true; - } else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() && - NewTemplateParm->hasDefaultArgument()) { + } else if (OldTemplateParm && + hasVisibleDefaultArgument(OldTemplateParm) && + NewTemplateParm->hasDefaultArgument()) { OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation(); NewDefaultLoc = NewTemplateParm->getDefaultArgument().getLocation(); SawDefaultArgument = true; @@ -1424,11 +1411,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, } else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument()) { // Merge the default argument from the old declaration to the // new declaration. - // FIXME: We need to create a new kind of "default argument" expression - // that points to a previous template template parameter. - NewTemplateParm->setDefaultArgument( - OldTemplateParm->getDefaultArgument(), - /*Inherited=*/ true); + NewTemplateParm->setInheritedDefaultArgument(Context, OldTemplateParm); PreviousDefaultArgLoc = OldTemplateParm->getDefaultArgument().getLocation(); } else if (NewTemplateParm->hasDefaultArgument()) { @@ -3316,7 +3299,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, HasDefaultArg = false; if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) { - if (!TypeParm->hasDefaultArgument()) + if (!hasVisibleDefaultArgument(TypeParm)) return TemplateArgumentLoc(); HasDefaultArg = true; @@ -3333,7 +3316,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, if (NonTypeTemplateParmDecl *NonTypeParm = dyn_cast<NonTypeTemplateParmDecl>(Param)) { - if (!NonTypeParm->hasDefaultArgument()) + if (!hasVisibleDefaultArgument(NonTypeParm)) return TemplateArgumentLoc(); HasDefaultArg = true; @@ -3351,7 +3334,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, TemplateTemplateParmDecl *TempTempParm = cast<TemplateTemplateParmDecl>(Param); - if (!TempTempParm->hasDefaultArgument()) + if (!hasVisibleDefaultArgument(TempTempParm)) return TemplateArgumentLoc(); HasDefaultArg = true; @@ -3661,6 +3644,35 @@ static Optional<unsigned> getExpandedPackSize(NamedDecl *Param) { return None; } +/// Diagnose a missing template argument. +template<typename TemplateParmDecl> +static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc, + TemplateDecl *TD, + const TemplateParmDecl *D, + TemplateArgumentListInfo &Args) { + // Dig out the most recent declaration of the template parameter; there may be + // declarations of the template that are more recent than TD. + D = cast<TemplateParmDecl>(cast<TemplateDecl>(TD->getMostRecentDecl()) + ->getTemplateParameters() + ->getParam(D->getIndex())); + + // If there's a default argument that's not visible, diagnose that we're + // missing a module import. + llvm::SmallVector<Module*, 8> Modules; + if (D->hasDefaultArgument() && !S.hasVisibleDefaultArgument(D, &Modules)) { + S.diagnoseMissingImport(Loc, cast<NamedDecl>(TD), + D->getDefaultArgumentLoc(), Modules, + Sema::MissingImportKind::DefaultArgument, + /*Recover*/ true); + return true; + } + + // FIXME: If there's a more recent default argument that *is* visible, + // diagnose that it was declared too late. + + return diagnoseArityMismatch(S, TD, Loc, Args); +} + /// \brief Check that the given template argument list is well-formed /// for specializing the given template. bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, @@ -3816,8 +3828,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // (when the template parameter was part of a nested template) into // the default argument. if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { - if (!TTP->hasDefaultArgument()) - return diagnoseArityMismatch(*this, Template, TemplateLoc, NewArgs); + if (!hasVisibleDefaultArgument(TTP)) + return diagnoseMissingArgument(*this, TemplateLoc, Template, TTP, + NewArgs); TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this, Template, @@ -3832,8 +3845,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, ArgType); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { - if (!NTTP->hasDefaultArgument()) - return diagnoseArityMismatch(*this, Template, TemplateLoc, NewArgs); + if (!hasVisibleDefaultArgument(NTTP)) + return diagnoseMissingArgument(*this, TemplateLoc, Template, NTTP, + NewArgs); ExprResult E = SubstDefaultTemplateArgument(*this, Template, TemplateLoc, @@ -3849,8 +3863,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(*Param); - if (!TempParm->hasDefaultArgument()) - return diagnoseArityMismatch(*this, Template, TemplateLoc, NewArgs); + if (!hasVisibleDefaultArgument(TempParm)) + return diagnoseMissingArgument(*this, TemplateLoc, Template, TempParm, + NewArgs); NestedNameSpecifierLoc QualifierLoc; TemplateName Name = SubstDefaultTemplateArgument(*this, Template, diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 5c994f8..f35d1aa 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1922,12 +1922,12 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( D->isParameterPack()); Inst->setAccess(AS_public); - if (D->hasDefaultArgument()) { + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { TypeSourceInfo *InstantiatedDefaultArg = SemaRef.SubstType(D->getDefaultArgumentInfo(), TemplateArgs, D->getDefaultArgumentLoc(), D->getDeclName()); if (InstantiatedDefaultArg) - Inst->setDefaultArgument(InstantiatedDefaultArg, false); + Inst->setDefaultArgument(InstantiatedDefaultArg); } // Introduce this template parameter's instantiation into the instantiation @@ -2078,10 +2078,10 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( if (Invalid) Param->setInvalidDecl(); - if (D->hasDefaultArgument()) { + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { ExprResult Value = SemaRef.SubstExpr(D->getDefaultArgument(), TemplateArgs); if (!Value.isInvalid()) - Param->setDefaultArgument(Value.get(), false); + Param->setDefaultArgument(Value.get()); } // Introduce this template parameter's instantiation into the instantiation @@ -2205,7 +2205,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl( D->getPosition(), D->isParameterPack(), D->getIdentifier(), InstParams); - if (D->hasDefaultArgument()) { + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { NestedNameSpecifierLoc QualifierLoc = D->getDefaultArgument().getTemplateQualifierLoc(); QualifierLoc = @@ -2215,10 +2215,10 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl( D->getDefaultArgument().getTemplateNameLoc(), TemplateArgs); if (!TName.isNull()) Param->setDefaultArgument( + SemaRef.Context, TemplateArgumentLoc(TemplateArgument(TName), D->getDefaultArgument().getTemplateQualifierLoc(), - D->getDefaultArgument().getTemplateNameLoc()), - false); + D->getDefaultArgument().getTemplateNameLoc())); } Param->setAccess(AS_public); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 628eb73..d72f259 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -22,8 +22,10 @@ #include "clang/AST/Expr.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeLocVisitor.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" @@ -121,6 +123,12 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, case AttributeList::AT_SPtr: \ case AttributeList::AT_UPtr +// Nullability qualifiers. +#define NULLABILITY_TYPE_ATTRS_CASELIST \ + case AttributeList::AT_TypeNonNull: \ + case AttributeList::AT_TypeNullable: \ + case AttributeList::AT_TypeNullUnspecified + namespace { /// An object which stores processing state for the entire /// GetTypeForDeclarator process. @@ -307,8 +315,12 @@ static bool handleObjCPointerTypeAttr(TypeProcessingState &state, /// /// \param i - a notional index which the search will start /// immediately inside +/// +/// \param onlyBlockPointers Whether we should only look into block +/// pointer types (vs. all pointer types). static DeclaratorChunk *maybeMovePastReturnType(Declarator &declarator, - unsigned i) { + unsigned i, + bool onlyBlockPointers) { assert(i <= declarator.getNumTypeObjects()); DeclaratorChunk *result = nullptr; @@ -329,20 +341,26 @@ static DeclaratorChunk *maybeMovePastReturnType(Declarator &declarator, return result; // If we do find a function declarator, scan inwards from that, - // looking for a block-pointer declarator. + // looking for a (block-)pointer declarator. case DeclaratorChunk::Function: for (--i; i != 0; --i) { - DeclaratorChunk &blockChunk = declarator.getTypeObject(i-1); - switch (blockChunk.Kind) { + DeclaratorChunk &ptrChunk = declarator.getTypeObject(i-1); + switch (ptrChunk.Kind) { case DeclaratorChunk::Paren: - case DeclaratorChunk::Pointer: case DeclaratorChunk::Array: case DeclaratorChunk::Function: case DeclaratorChunk::Reference: - case DeclaratorChunk::MemberPointer: continue; + + case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pointer: + if (onlyBlockPointers) + continue; + + // fallthrough + case DeclaratorChunk::BlockPointer: - result = &blockChunk; + result = &ptrChunk; goto continue_outer; } llvm_unreachable("bad declarator chunk kind"); @@ -382,7 +400,8 @@ static void distributeObjCPointerTypeAttr(TypeProcessingState &state, DeclaratorChunk *destChunk = nullptr; if (state.isProcessingDeclSpec() && attr.getKind() == AttributeList::AT_ObjCOwnership) - destChunk = maybeMovePastReturnType(declarator, i - 1); + destChunk = maybeMovePastReturnType(declarator, i - 1, + /*onlyBlockPointers=*/true); if (!destChunk) destChunk = &chunk; moveAttrFromListToList(attr, state.getCurrentAttrListRef(), @@ -398,7 +417,9 @@ static void distributeObjCPointerTypeAttr(TypeProcessingState &state, case DeclaratorChunk::Function: if (state.isProcessingDeclSpec() && attr.getKind() == AttributeList::AT_ObjCOwnership) { - if (DeclaratorChunk *dest = maybeMovePastReturnType(declarator, i)) { + if (DeclaratorChunk *dest = maybeMovePastReturnType( + declarator, i, + /*onlyBlockPointers=*/true)) { moveAttrFromListToList(attr, state.getCurrentAttrListRef(), dest->getAttrListRef()); return; @@ -620,6 +641,10 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, // Microsoft type attributes cannot go after the declarator-id. continue; + NULLABILITY_TYPE_ATTRS_CASELIST: + // Nullability specifiers cannot go after the declarator-id. + continue; + default: break; } @@ -2529,6 +2554,285 @@ getCCForDeclaratorChunk(Sema &S, Declarator &D, return CC; } +namespace { + /// A simple notion of pointer kinds, which matches up with the various + /// pointer declarators. + enum class SimplePointerKind { + Pointer, + BlockPointer, + MemberPointer, + }; +} + +IdentifierInfo *Sema::getNullabilityKeyword(NullabilityKind nullability) { + switch (nullability) { + case NullabilityKind::NonNull: + if (!Ident___nonnull) + Ident___nonnull = PP.getIdentifierInfo("__nonnull"); + return Ident___nonnull; + + case NullabilityKind::Nullable: + if (!Ident___nullable) + Ident___nullable = PP.getIdentifierInfo("__nullable"); + return Ident___nullable; + + case NullabilityKind::Unspecified: + if (!Ident___null_unspecified) + Ident___null_unspecified = PP.getIdentifierInfo("__null_unspecified"); + return Ident___null_unspecified; + } + llvm_unreachable("Unknown nullability kind."); +} + +/// Retrieve the identifier "NSError". +IdentifierInfo *Sema::getNSErrorIdent() { + if (!Ident_NSError) + Ident_NSError = PP.getIdentifierInfo("NSError"); + + return Ident_NSError; +} + +/// Check whether there is a nullability attribute of any kind in the given +/// attribute list. +static bool hasNullabilityAttr(const AttributeList *attrs) { + for (const AttributeList *attr = attrs; attr; + attr = attr->getNext()) { + if (attr->getKind() == AttributeList::AT_TypeNonNull || + attr->getKind() == AttributeList::AT_TypeNullable || + attr->getKind() == AttributeList::AT_TypeNullUnspecified) + return true; + } + + return false; +} + +namespace { + /// Describes the kind of a pointer a declarator describes. + enum class PointerDeclaratorKind { + // Not a pointer. + NonPointer, + // Single-level pointer. + SingleLevelPointer, + // Multi-level pointer (of any pointer kind). + MultiLevelPointer, + // CFFooRef* + MaybePointerToCFRef, + // CFErrorRef* + CFErrorRefPointer, + // NSError** + NSErrorPointerPointer, + }; +} + +/// Classify the given declarator, whose type-specified is \c type, based on +/// what kind of pointer it refers to. +/// +/// This is used to determine the default nullability. +static PointerDeclaratorKind classifyPointerDeclarator(Sema &S, + QualType type, + Declarator &declarator) { + unsigned numNormalPointers = 0; + + // For any dependent type, we consider it a non-pointer. + if (type->isDependentType()) + return PointerDeclaratorKind::NonPointer; + + // Look through the declarator chunks to identify pointers. + for (unsigned i = 0, n = declarator.getNumTypeObjects(); i != n; ++i) { + DeclaratorChunk &chunk = declarator.getTypeObject(i); + switch (chunk.Kind) { + case DeclaratorChunk::Array: + case DeclaratorChunk::Function: + break; + + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::MemberPointer: + return numNormalPointers > 0 ? PointerDeclaratorKind::MultiLevelPointer + : PointerDeclaratorKind::SingleLevelPointer; + + case DeclaratorChunk::Paren: + case DeclaratorChunk::Reference: + continue; + + case DeclaratorChunk::Pointer: + ++numNormalPointers; + if (numNormalPointers > 2) + return PointerDeclaratorKind::MultiLevelPointer; + continue; + } + } + + // Then, dig into the type specifier itself. + unsigned numTypeSpecifierPointers = 0; + do { + // Decompose normal pointers. + if (auto ptrType = type->getAs<PointerType>()) { + ++numNormalPointers; + + if (numNormalPointers > 2) + return PointerDeclaratorKind::MultiLevelPointer; + + type = ptrType->getPointeeType(); + ++numTypeSpecifierPointers; + continue; + } + + // Decompose block pointers. + if (type->getAs<BlockPointerType>()) { + return numNormalPointers > 0 ? PointerDeclaratorKind::MultiLevelPointer + : PointerDeclaratorKind::SingleLevelPointer; + } + + // Decompose member pointers. + if (type->getAs<MemberPointerType>()) { + return numNormalPointers > 0 ? PointerDeclaratorKind::MultiLevelPointer + : PointerDeclaratorKind::SingleLevelPointer; + } + + // Look at Objective-C object pointers. + if (auto objcObjectPtr = type->getAs<ObjCObjectPointerType>()) { + ++numNormalPointers; + ++numTypeSpecifierPointers; + + // If this is NSError**, report that. + if (auto objcClassDecl = objcObjectPtr->getInterfaceDecl()) { + if (objcClassDecl->getIdentifier() == S.getNSErrorIdent() && + numNormalPointers == 2 && numTypeSpecifierPointers < 2) { + return PointerDeclaratorKind::NSErrorPointerPointer; + } + } + + break; + } + + // Look at Objective-C class types. + if (auto objcClass = type->getAs<ObjCInterfaceType>()) { + if (objcClass->getInterface()->getIdentifier() == S.getNSErrorIdent()) { + if (numNormalPointers == 2 && numTypeSpecifierPointers < 2) + return PointerDeclaratorKind::NSErrorPointerPointer;; + } + + break; + } + + // If at this point we haven't seen a pointer, we won't see one. + if (numNormalPointers == 0) + return PointerDeclaratorKind::NonPointer; + + if (auto recordType = type->getAs<RecordType>()) { + RecordDecl *recordDecl = recordType->getDecl(); + + bool isCFError = false; + if (S.CFError) { + // If we already know about CFError, test it directly. + isCFError = (S.CFError == recordDecl); + } else { + // Check whether this is CFError, which we identify based on its bridge + // to NSError. + if (recordDecl->getTagKind() == TTK_Struct && numNormalPointers > 0) { + if (auto bridgeAttr = recordDecl->getAttr<ObjCBridgeAttr>()) { + if (bridgeAttr->getBridgedType() == S.getNSErrorIdent()) { + S.CFError = recordDecl; + isCFError = true; + } + } + } + } + + // If this is CFErrorRef*, report it as such. + if (isCFError && numNormalPointers == 2 && numTypeSpecifierPointers < 2) { + return PointerDeclaratorKind::CFErrorRefPointer; + } + break; + } + + break; + } while (true); + + + switch (numNormalPointers) { + case 0: + return PointerDeclaratorKind::NonPointer; + + case 1: + return PointerDeclaratorKind::SingleLevelPointer; + + case 2: + return PointerDeclaratorKind::MaybePointerToCFRef; + + default: + return PointerDeclaratorKind::MultiLevelPointer; + } +} + +static FileID getNullabilityCompletenessCheckFileID(Sema &S, + SourceLocation loc) { + // If we're anywhere in a function, method, or closure context, don't perform + // completeness checks. + for (DeclContext *ctx = S.CurContext; ctx; ctx = ctx->getParent()) { + if (ctx->isFunctionOrMethod()) + return FileID(); + + if (ctx->isFileContext()) + break; + } + + // We only care about the expansion location. + loc = S.SourceMgr.getExpansionLoc(loc); + FileID file = S.SourceMgr.getFileID(loc); + if (file.isInvalid()) + return FileID(); + + // Retrieve file information. + bool invalid = false; + const SrcMgr::SLocEntry &sloc = S.SourceMgr.getSLocEntry(file, &invalid); + if (invalid || !sloc.isFile()) + return FileID(); + + // We don't want to perform completeness checks on the main file or in + // system headers. + const SrcMgr::FileInfo &fileInfo = sloc.getFile(); + if (fileInfo.getIncludeLoc().isInvalid()) + return FileID(); + if (fileInfo.getFileCharacteristic() != SrcMgr::C_User && + S.Diags.getSuppressSystemWarnings()) { + return FileID(); + } + + return file; +} + +/// Check for consistent use of nullability. +static void checkNullabilityConsistency(TypeProcessingState &state, + SimplePointerKind pointerKind, + SourceLocation pointerLoc) { + Sema &S = state.getSema(); + + // Determine which file we're performing consistency checking for. + FileID file = getNullabilityCompletenessCheckFileID(S, pointerLoc); + if (file.isInvalid()) + return; + + // If we haven't seen any type nullability in this file, we won't warn now + // about anything. + FileNullability &fileNullability = S.NullabilityMap[file]; + if (!fileNullability.SawTypeNullability) { + // If this is the first pointer declarator in the file, record it. + if (fileNullability.PointerLoc.isInvalid() && + !S.Context.getDiagnostics().isIgnored(diag::warn_nullability_missing, + pointerLoc)) { + fileNullability.PointerLoc = pointerLoc; + fileNullability.PointerKind = static_cast<unsigned>(pointerKind); + } + + return; + } + + // Complain about missing nullability. + S.Diag(pointerLoc, diag::warn_nullability_missing) + << static_cast<unsigned>(pointerKind); +} + static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, QualType declSpecType, TypeSourceInfo *TInfo) { @@ -2596,6 +2900,245 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } } + // Determine whether we should infer __nonnull on pointer types. + Optional<NullabilityKind> inferNullability; + bool inferNullabilityCS = false; + bool inferNullabilityInnerOnly = false; + bool inferNullabilityInnerOnlyComplete = false; + + // Are we in an assume-nonnull region? + bool inAssumeNonNullRegion = false; + if (S.PP.getPragmaAssumeNonNullLoc().isValid() && + !state.getDeclarator().isObjCWeakProperty() && + !S.deduceWeakPropertyFromType(T)) { + inAssumeNonNullRegion = true; + // Determine which file we saw the assume-nonnull region in. + FileID file = getNullabilityCompletenessCheckFileID( + S, S.PP.getPragmaAssumeNonNullLoc()); + if (!file.isInvalid()) { + FileNullability &fileNullability = S.NullabilityMap[file]; + + // If we haven't seen any type nullability before, now we have. + if (!fileNullability.SawTypeNullability) { + if (fileNullability.PointerLoc.isValid()) { + S.Diag(fileNullability.PointerLoc, diag::warn_nullability_missing) + << static_cast<unsigned>(fileNullability.PointerKind); + } + + fileNullability.SawTypeNullability = true; + } + } + } + + // Whether to complain about missing nullability specifiers or not. + enum { + /// Never complain. + CAMN_No, + /// Complain on the inner pointers (but not the outermost + /// pointer). + CAMN_InnerPointers, + /// Complain about any pointers that don't have nullability + /// specified or inferred. + CAMN_Yes + } complainAboutMissingNullability = CAMN_No; + unsigned NumPointersRemaining = 0; + + if (IsTypedefName) { + // For typedefs, we do not infer any nullability (the default), + // and we only complain about missing nullability specifiers on + // inner pointers. + complainAboutMissingNullability = CAMN_InnerPointers; + + if (T->canHaveNullability() && !T->getNullability(S.Context)) { + ++NumPointersRemaining; + } + + for (unsigned i = 0, n = D.getNumTypeObjects(); i != n; ++i) { + DeclaratorChunk &chunk = D.getTypeObject(i); + switch (chunk.Kind) { + case DeclaratorChunk::Array: + case DeclaratorChunk::Function: + break; + + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::MemberPointer: + ++NumPointersRemaining; + break; + + case DeclaratorChunk::Paren: + case DeclaratorChunk::Reference: + continue; + + case DeclaratorChunk::Pointer: + ++NumPointersRemaining; + continue; + } + } + } else { + bool isFunctionOrMethod = false; + switch (auto context = state.getDeclarator().getContext()) { + case Declarator::ObjCParameterContext: + case Declarator::ObjCResultContext: + case Declarator::PrototypeContext: + case Declarator::TrailingReturnContext: + isFunctionOrMethod = true; + // fallthrough + + case Declarator::MemberContext: + if (state.getDeclarator().isObjCIvar() && !isFunctionOrMethod) { + complainAboutMissingNullability = CAMN_No; + break; + } + // fallthrough + + case Declarator::FileContext: + case Declarator::KNRTypeListContext: + complainAboutMissingNullability = CAMN_Yes; + + // Nullability inference depends on the type and declarator. + switch (classifyPointerDeclarator(S, T, D)) { + case PointerDeclaratorKind::NonPointer: + case PointerDeclaratorKind::MultiLevelPointer: + // Cannot infer nullability. + break; + + case PointerDeclaratorKind::SingleLevelPointer: + // Infer __nonnull if we are in an assumes-nonnull region. + if (inAssumeNonNullRegion) { + inferNullability = NullabilityKind::NonNull; + inferNullabilityCS = (context == Declarator::ObjCParameterContext || + context == Declarator::ObjCResultContext); + } + break; + + case PointerDeclaratorKind::CFErrorRefPointer: + case PointerDeclaratorKind::NSErrorPointerPointer: + // Within a function or method signature, infer __nullable at both + // levels. + if (isFunctionOrMethod && inAssumeNonNullRegion) + inferNullability = NullabilityKind::Nullable; + break; + + case PointerDeclaratorKind::MaybePointerToCFRef: + if (isFunctionOrMethod) { + // On pointer-to-pointer parameters marked cf_returns_retained or + // cf_returns_not_retained, if the outer pointer is explicit then + // infer the inner pointer as __nullable. + auto hasCFReturnsAttr = [](const AttributeList *NextAttr) -> bool { + while (NextAttr) { + if (NextAttr->getKind() == AttributeList::AT_CFReturnsRetained || + NextAttr->getKind() == AttributeList::AT_CFReturnsNotRetained) + return true; + NextAttr = NextAttr->getNext(); + } + return false; + }; + if (const auto *InnermostChunk = D.getInnermostNonParenChunk()) { + if (hasCFReturnsAttr(D.getAttributes()) || + hasCFReturnsAttr(InnermostChunk->getAttrs()) || + hasCFReturnsAttr(D.getDeclSpec().getAttributes().getList())) { + inferNullability = NullabilityKind::Nullable; + inferNullabilityInnerOnly = true; + } + } + } + break; + } + break; + + case Declarator::ConversionIdContext: + complainAboutMissingNullability = CAMN_Yes; + break; + + case Declarator::AliasDeclContext: + case Declarator::AliasTemplateContext: + case Declarator::BlockContext: + case Declarator::BlockLiteralContext: + case Declarator::ConditionContext: + case Declarator::CXXCatchContext: + case Declarator::CXXNewContext: + case Declarator::ForContext: + case Declarator::LambdaExprContext: + case Declarator::LambdaExprParameterContext: + case Declarator::ObjCCatchContext: + case Declarator::TemplateParamContext: + case Declarator::TemplateTypeArgContext: + case Declarator::TypeNameContext: + // Don't infer in these contexts. + break; + } + } + + // Local function that checks the nullability for a given pointer declarator. + // Returns true if __nonnull was inferred. + auto inferPointerNullability = [&](SimplePointerKind pointerKind, + SourceLocation pointerLoc, + AttributeList *&attrs) -> AttributeList * { + // We've seen a pointer. + if (NumPointersRemaining > 0) + --NumPointersRemaining; + + // If a nullability attribute is present, there's nothing to do. + if (hasNullabilityAttr(attrs)) + return nullptr; + + // If we're supposed to infer nullability, do so now. + if (inferNullability && !inferNullabilityInnerOnlyComplete) { + AttributeList::Syntax syntax + = inferNullabilityCS ? AttributeList::AS_ContextSensitiveKeyword + : AttributeList::AS_Keyword; + AttributeList *nullabilityAttr = state.getDeclarator().getAttributePool() + .create( + S.getNullabilityKeyword( + *inferNullability), + SourceRange(pointerLoc), + nullptr, SourceLocation(), + nullptr, 0, syntax); + + spliceAttrIntoList(*nullabilityAttr, attrs); + + if (inferNullabilityInnerOnly) + inferNullabilityInnerOnlyComplete = true; + return nullabilityAttr; + } + + // If we're supposed to complain about missing nullability, do so + // now if it's truly missing. + switch (complainAboutMissingNullability) { + case CAMN_No: + break; + + case CAMN_InnerPointers: + if (NumPointersRemaining == 0) + break; + // Fallthrough. + + case CAMN_Yes: + checkNullabilityConsistency(state, pointerKind, pointerLoc); + } + + return nullptr; + }; + + // If the type itself could have nullability but does not, infer pointer + // nullability and perform consistency checking. + if (T->canHaveNullability() && S.ActiveTemplateInstantiations.empty() && + !T->getNullability(S.Context)) { + SimplePointerKind pointerKind = SimplePointerKind::Pointer; + if (T->isBlockPointerType()) + pointerKind = SimplePointerKind::BlockPointer; + else if (T->isMemberPointerType()) + pointerKind = SimplePointerKind::MemberPointer; + + if (auto *attr = inferPointerNullability( + pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(), + D.getMutableDeclSpec().getAttributes().getListRef())) { + T = Context.getAttributedType( + AttributedType::getNullabilityAttrKind(*inferNullability), T, T); + attr->setUsedAsTypeAttr(); + } + } + // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). @@ -2613,6 +3156,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (!LangOpts.Blocks) S.Diag(DeclType.Loc, diag::err_blocks_disable); + // Handle pointer nullability. + inferPointerNullability(SimplePointerKind::BlockPointer, + DeclType.Loc, DeclType.getAttrListRef()); + T = S.BuildBlockPointerType(T, D.getIdentifierLoc(), Name); if (DeclType.Cls.TypeQuals) T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Cls.TypeQuals); @@ -2625,6 +3172,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, D.setInvalidType(true); // Build the type anyway. } + + // Handle pointer nullability + inferPointerNullability(SimplePointerKind::Pointer, DeclType.Loc, + DeclType.getAttrListRef()); + if (LangOpts.ObjC1 && T->getAs<ObjCObjectType>()) { T = Context.getObjCObjectPointerType(T); if (DeclType.Ptr.TypeQuals) @@ -3066,6 +3618,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // The scope spec must refer to a class, or be dependent. CXXScopeSpec &SS = DeclType.Mem.Scope(); QualType ClsType; + + // Handle pointer nullability. + inferPointerNullability(SimplePointerKind::MemberPointer, + DeclType.Loc, DeclType.getAttrListRef()); + if (SS.isInvalid()) { // Avoid emitting extra errors if we already errored on the scope. D.setInvalidType(true); @@ -3495,6 +4052,12 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) { return AttributeList::AT_SPtr; case AttributedType::attr_uptr: return AttributeList::AT_UPtr; + case AttributedType::attr_nonnull: + return AttributeList::AT_TypeNonNull; + case AttributedType::attr_nullable: + return AttributeList::AT_TypeNullable; + case AttributedType::attr_null_unspecified: + return AttributeList::AT_TypeNullUnspecified; } llvm_unreachable("unexpected attribute kind!"); } @@ -4114,7 +4677,8 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, // just be the return type of a block pointer. if (state.isProcessingDeclSpec()) { Declarator &D = state.getDeclarator(); - if (maybeMovePastReturnType(D, D.getNumTypeObjects())) + if (maybeMovePastReturnType(D, D.getNumTypeObjects(), + /*onlyBlockPointers=*/true)) return false; } } @@ -4491,6 +5055,212 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, return false; } +bool Sema::checkNullabilityTypeSpecifier(QualType &type, + NullabilityKind nullability, + SourceLocation nullabilityLoc, + bool isContextSensitive) { + // We saw a nullability type specifier. If this is the first one for + // this file, note that. + FileID file = getNullabilityCompletenessCheckFileID(*this, nullabilityLoc); + if (!file.isInvalid()) { + FileNullability &fileNullability = NullabilityMap[file]; + if (!fileNullability.SawTypeNullability) { + // If we have already seen a pointer declarator without a nullability + // annotation, complain about it. + if (fileNullability.PointerLoc.isValid()) { + Diag(fileNullability.PointerLoc, diag::warn_nullability_missing) + << static_cast<unsigned>(fileNullability.PointerKind); + } + + fileNullability.SawTypeNullability = true; + } + } + + // Check for existing nullability attributes on the type. + QualType desugared = type; + while (auto attributed = dyn_cast<AttributedType>(desugared.getTypePtr())) { + // Check whether there is already a null + if (auto existingNullability = attributed->getImmediateNullability()) { + // Duplicated nullability. + if (nullability == *existingNullability) { + Diag(nullabilityLoc, diag::warn_nullability_duplicate) + << static_cast<unsigned>(nullability) + << isContextSensitive + << FixItHint::CreateRemoval(nullabilityLoc); + + break; + } + + // Conflicting nullability. + Diag(nullabilityLoc, diag::err_nullability_conflicting) + << static_cast<unsigned>(nullability) + << isContextSensitive + << static_cast<unsigned>(*existingNullability) + << false; + return true; + } + + desugared = attributed->getModifiedType(); + } + + // If there is already a different nullability specifier, complain. + // This (unlike the code above) looks through typedefs that might + // have nullability specifiers on them, which means we cannot + // provide a useful Fix-It. + if (auto existingNullability = desugared->getNullability(Context)) { + if (nullability != *existingNullability) { + Diag(nullabilityLoc, diag::err_nullability_conflicting) + << static_cast<unsigned>(nullability) + << isContextSensitive + << static_cast<unsigned>(*existingNullability) + << false; + + // Try to find the typedef with the existing nullability specifier. + if (auto typedefType = desugared->getAs<TypedefType>()) { + TypedefNameDecl *typedefDecl = typedefType->getDecl(); + QualType underlyingType = typedefDecl->getUnderlyingType(); + if (auto typedefNullability + = AttributedType::stripOuterNullability(underlyingType)) { + if (*typedefNullability == *existingNullability) { + Diag(typedefDecl->getLocation(), diag::note_nullability_here) + << static_cast<unsigned>(*existingNullability); + } + } + } + + return true; + } + } + + // If this definitely isn't a pointer type, reject the specifier. + if (!desugared->canHaveNullability()) { + Diag(nullabilityLoc, diag::err_nullability_nonpointer) + << static_cast<unsigned>(nullability) << isContextSensitive << type; + return true; + } + + // For the context-sensitive keywords/Objective-C property + // attributes, require that the type be a single-level pointer. + if (isContextSensitive) { + // Make sure that the pointee isn't itself a pointer type. + QualType pointeeType = desugared->getPointeeType(); + if (pointeeType->isAnyPointerType() || + pointeeType->isObjCObjectPointerType() || + pointeeType->isMemberPointerType()) { + Diag(nullabilityLoc, diag::err_nullability_cs_multilevel) + << static_cast<unsigned>(nullability) + << type; + Diag(nullabilityLoc, diag::note_nullability_type_specifier) + << static_cast<unsigned>(nullability) + << type + << FixItHint::CreateReplacement(nullabilityLoc, + getNullabilitySpelling(nullability)); + return true; + } + } + + // Form the attributed type. + type = Context.getAttributedType( + AttributedType::getNullabilityAttrKind(nullability), type, type); + return false; +} + +/// Map a nullability attribute kind to a nullability kind. +static NullabilityKind mapNullabilityAttrKind(AttributeList::Kind kind) { + switch (kind) { + case AttributeList::AT_TypeNonNull: + return NullabilityKind::NonNull; + + case AttributeList::AT_TypeNullable: + return NullabilityKind::Nullable; + + case AttributeList::AT_TypeNullUnspecified: + return NullabilityKind::Unspecified; + + default: + llvm_unreachable("not a nullability attribute kind"); + } +} + +/// Distribute a nullability type attribute that cannot be applied to +/// the type specifier to a pointer, block pointer, or member pointer +/// declarator, complaining if necessary. +/// +/// \returns true if the nullability annotation was distributed, false +/// otherwise. +static bool distributeNullabilityTypeAttr(TypeProcessingState &state, + QualType type, + AttributeList &attr) { + Declarator &declarator = state.getDeclarator(); + + /// Attempt to move the attribute to the specified chunk. + auto moveToChunk = [&](DeclaratorChunk &chunk, bool inFunction) -> bool { + // If there is already a nullability attribute there, don't add + // one. + if (hasNullabilityAttr(chunk.getAttrListRef())) + return false; + + // Complain about the nullability qualifier being in the wrong + // place. + unsigned pointerKind + = chunk.Kind == DeclaratorChunk::Pointer ? (inFunction ? 3 : 0) + : chunk.Kind == DeclaratorChunk::BlockPointer ? 1 + : inFunction? 4 : 2; + + auto diag = state.getSema().Diag(attr.getLoc(), + diag::warn_nullability_declspec) + << static_cast<unsigned>(mapNullabilityAttrKind(attr.getKind())) + << type + << pointerKind; + + // FIXME: MemberPointer chunks don't carry the location of the *. + if (chunk.Kind != DeclaratorChunk::MemberPointer) { + diag << FixItHint::CreateRemoval(attr.getLoc()) + << FixItHint::CreateInsertion( + state.getSema().getPreprocessor() + .getLocForEndOfToken(chunk.Loc), + " " + attr.getName()->getName().str() + " "); + } + + moveAttrFromListToList(attr, state.getCurrentAttrListRef(), + chunk.getAttrListRef()); + return true; + }; + + // Move it to the outermost pointer, member pointer, or block + // pointer declarator. + for (unsigned i = state.getCurrentChunkIndex(); i != 0; --i) { + DeclaratorChunk &chunk = declarator.getTypeObject(i-1); + switch (chunk.Kind) { + case DeclaratorChunk::Pointer: + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::MemberPointer: + return moveToChunk(chunk, false); + + case DeclaratorChunk::Paren: + case DeclaratorChunk::Array: + continue; + + case DeclaratorChunk::Function: + // Try to move past the return type to a function/block/member + // function pointer. + if (DeclaratorChunk *dest = maybeMovePastReturnType( + declarator, i, + /*onlyBlockPointers=*/false)) { + return moveToChunk(*dest, true); + } + + return false; + + // Don't walk through these. + case DeclaratorChunk::Reference: + return false; + } + } + + return false; +} + static AttributedType::Kind getCCTypeAttrKind(AttributeList &Attr) { assert(!Attr.isInvalid()); switch (Attr.getKind()) { @@ -4997,6 +5767,24 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, attr.setUsedAsTypeAttr(); break; + NULLABILITY_TYPE_ATTRS_CASELIST: + // Either add nullability here or try to distribute it. We + // don't want to distribute the nullability specifier past any + // dependent type, because that complicates the user model. + if (type->canHaveNullability() || type->isDependentType() || + !distributeNullabilityTypeAttr(state, type, attr)) { + if (state.getSema().checkNullabilityTypeSpecifier( + type, + mapNullabilityAttrKind(attr.getKind()), + attr.getLoc(), + attr.isContextSensitiveKeywordAttribute())) { + attr.setInvalid(); + } + + attr.setUsedAsTypeAttr(); + } + break; + case AttributeList::AT_NSReturnsRetained: if (!state.getSema().getLangOpts().ObjCAutoRefCount) break; @@ -5153,7 +5941,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, /// in order to provide a definition of this entity. bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested) { // Easy case: if we don't have modules, all declarations are visible. - if (!getLangOpts().Modules) + if (!getLangOpts().Modules && !getLangOpts().ModulesLocalVisibility) return true; // If this definition was instantiated from a template, map back to the @@ -5185,10 +5973,18 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested) { } assert(D && "missing definition for pattern of instantiated definition"); - // FIXME: If we merged any other decl into D, and that declaration is visible, - // then we should consider a definition to be visible. *Suggested = D; - return LookupResult::isVisible(*this, D); + if (LookupResult::isVisible(*this, D)) + return true; + + // The external source may have additional definitions of this type that are + // visible, so complete the redeclaration chain now and ask again. + if (auto *Source = Context.getExternalSource()) { + Source->CompleteRedeclChain(D); + return LookupResult::isVisible(*this, D); + } + + return false; } /// Locks in the inheritance model for the given class and all of its bases. @@ -5239,20 +6035,8 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // If we know about the definition but it is not visible, complain. NamedDecl *SuggestedDef = nullptr; if (!Diagnoser.Suppressed && Def && - !hasVisibleDefinition(Def, &SuggestedDef)) { - // Suppress this error outside of a SFINAE context if we've already - // emitted the error once for this type. There's no usefulness in - // repeating the diagnostic. - // FIXME: Add a Fix-It that imports the corresponding module or includes - // the header. - Module *Owner = getOwningModule(SuggestedDef); - Diag(Loc, diag::err_module_private_definition) - << T << Owner->getFullModuleName(); - Diag(SuggestedDef->getLocation(), diag::note_previous_definition); - - // Try to recover by implicitly importing this module. - createImplicitModuleImportForErrorRecovery(Loc, Owner); - } + !hasVisibleDefinition(Def, &SuggestedDef)) + diagnoseMissingImport(Loc, SuggestedDef, /*NeedDefinition*/true); // We lock in the inheritance model once somebody has asked us to ensure // that a pointer-to-member type is complete. diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index f5249fd..73dde7c 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -5386,6 +5386,17 @@ QualType TreeTransform<Derived>::TransformAttributedType( = getDerived().TransformType(oldType->getEquivalentType()); if (equivalentType.isNull()) return QualType(); + + // Check whether we can add nullability; it is only represented as + // type sugar, and therefore cannot be diagnosed in any other way. + if (auto nullability = oldType->getImmediateNullability()) { + if (!modifiedType->canHaveNullability()) { + SemaRef.Diag(TL.getAttrNameLoc(), diag::err_nullability_nonpointer) + << static_cast<unsigned>(*nullability) << false << modifiedType; + return QualType(); + } + } + result = SemaRef.Context.getAttributedType(oldType->getAttrKind(), modifiedType, equivalentType); @@ -6871,6 +6882,17 @@ TreeTransform<Derived>::TransformOMPTaskwaitDirective(OMPTaskwaitDirective *D) { } template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPTaskgroupDirective( + OMPTaskgroupDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_taskgroup, DirName, nullptr, + D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> StmtResult TreeTransform<Derived>::TransformOMPFlushDirective(OMPFlushDirective *D) { DeclarationNameInfo DirName; @@ -7950,6 +7972,25 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) { E->usesGNUSyntax(), Init.get()); } +// Seems that if TransformInitListExpr() only works on the syntactic form of an +// InitListExpr, then a DesignatedInitUpdateExpr is not encountered. +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformDesignatedInitUpdateExpr( + DesignatedInitUpdateExpr *E) { + llvm_unreachable("Unexpected DesignatedInitUpdateExpr in syntactic form of " + "initializer"); + return ExprError(); +} + +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformNoInitExpr( + NoInitExpr *E) { + llvm_unreachable("Unexpected NoInitExpr in syntactic form of initializer"); + return ExprError(); +} + template<typename Derived> ExprResult TreeTransform<Derived>::TransformImplicitValueInitExpr( |