diff options
author | dim <dim@FreeBSD.org> | 2012-12-02 13:20:44 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2012-12-02 13:20:44 +0000 |
commit | 056abd2059c65a3e908193aeae16fad98017437c (patch) | |
tree | 2732d02d7d51218d6eed98ac7fcfc5b8794896b5 /lib/Sema/SemaDecl.cpp | |
parent | cc73504950eb7b5dff2dded9bedd67bc36d64641 (diff) | |
download | FreeBSD-src-056abd2059c65a3e908193aeae16fad98017437c.zip FreeBSD-src-056abd2059c65a3e908193aeae16fad98017437c.tar.gz |
Vendor import of clang release_32 branch r168974 (effectively, 3.2 RC2):
http://llvm.org/svn/llvm-project/cfe/branches/release_32@168974
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 840 |
1 files changed, 522 insertions, 318 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index ea181de..0092d5d 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -350,8 +350,8 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, /// isTagName() - This method is called *for error recovery purposes only* /// to determine if the specified name is a valid tag name ("struct foo"). If /// so, this returns the TST for the tag corresponding to it (TST_enum, -/// TST_union, TST_struct, TST_class). This is used to diagnose cases in C -/// where the user forgot to specify the tag. +/// TST_union, TST_struct, TST_interface, TST_class). This is used to diagnose +/// cases in C where the user forgot to specify the tag. DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { // Do a tag name lookup in this scope. LookupResult R(*this, &II, SourceLocation(), LookupTagName); @@ -361,6 +361,7 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { if (const TagDecl *TD = R.getAsSingle<TagDecl>()) { switch (TD->getTagKind()) { case TTK_Struct: return DeclSpec::TST_struct; + case TTK_Interface: return DeclSpec::TST_interface; case TTK_Union: return DeclSpec::TST_union; case TTK_Class: return DeclSpec::TST_class; case TTK_Enum: return DeclSpec::TST_enum; @@ -434,7 +435,8 @@ bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, else if (DeclContext *DC = computeDeclContext(*SS, false)) Diag(IILoc, diag::err_unknown_nested_typename_suggest) << II << DC << CorrectedQuotedStr << SS->getRange() - << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr); + << FixItHint::CreateReplacement(Corrected.getCorrectionRange(), + CorrectedStr); else llvm_unreachable("could not have corrected a typo here"); @@ -517,9 +519,9 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result, Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc) { - Result.clear(Sema::LookupTagName); - SemaRef.LookupParsedName(Result, S, &SS); - if (TagDecl *Tag = Result.getAsSingle<TagDecl>()) { + LookupResult R(SemaRef, Name, NameLoc, Sema::LookupTagName); + SemaRef.LookupParsedName(R, S, &SS); + if (TagDecl *Tag = R.getAsSingle<TagDecl>()) { const char *TagName = 0; const char *FixItTagName = 0; switch (Tag->getTagKind()) { @@ -538,6 +540,11 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result, FixItTagName = "struct "; break; + case TTK_Interface: + TagName = "__interface"; + FixItTagName = "__interface "; + break; + case TTK_Union: TagName = "union"; FixItTagName = "union "; @@ -548,25 +555,42 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result, << Name << TagName << SemaRef.getLangOpts().CPlusPlus << FixItHint::CreateInsertion(NameLoc, FixItTagName); - LookupResult R(SemaRef, Name, NameLoc, Sema::LookupOrdinaryName); - if (SemaRef.LookupParsedName(R, S, &SS)) { - for (LookupResult::iterator I = R.begin(), IEnd = R.end(); - I != IEnd; ++I) - SemaRef.Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type) - << Name << TagName; - } + for (LookupResult::iterator I = Result.begin(), IEnd = Result.end(); + I != IEnd; ++I) + SemaRef.Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type) + << Name << TagName; + + // Replace lookup results with just the tag decl. + Result.clear(Sema::LookupTagName); + SemaRef.LookupParsedName(Result, S, &SS); return true; } - Result.clear(Sema::LookupOrdinaryName); return false; } +/// Build a ParsedType for a simple-type-specifier with a nested-name-specifier. +static ParsedType buildNestedType(Sema &S, CXXScopeSpec &SS, + QualType T, SourceLocation NameLoc) { + ASTContext &Context = S.Context; + + TypeLocBuilder Builder; + Builder.pushTypeSpec(T).setNameLoc(NameLoc); + + T = S.getElaboratedType(ETK_None, SS, T); + ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T); + ElabTL.setElaboratedKeywordLoc(SourceLocation()); + ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); + return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); +} + Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc, - const Token &NextToken) { + const Token &NextToken, + bool IsAddressOfOperand, + CorrectionCandidateCallback *CCC) { DeclarationNameInfo NameInfo(Name, NameLoc); ObjCMethodDecl *CurMethod = getCurMethodDecl(); @@ -632,25 +656,11 @@ Corrected: // Perform typo correction to determine if there is another name that is // close to this name. - if (!SecondTry) { + if (!SecondTry && CCC) { SecondTry = true; - CorrectionCandidateCallback DefaultValidator; - // Try to limit which sets of keywords should be included in typo - // correction based on what the next token is. - DefaultValidator.WantTypeSpecifiers = - NextToken.is(tok::l_paren) || NextToken.is(tok::less) || - NextToken.is(tok::identifier) || NextToken.is(tok::star) || - NextToken.is(tok::amp) || NextToken.is(tok::l_square); - DefaultValidator.WantExpressionKeywords = - NextToken.is(tok::l_paren) || NextToken.is(tok::identifier) || - NextToken.is(tok::arrow) || NextToken.is(tok::period); - DefaultValidator.WantRemainingKeywords = - NextToken.is(tok::l_paren) || NextToken.is(tok::semi) || - NextToken.is(tok::identifier) || NextToken.is(tok::l_brace); - DefaultValidator.WantCXXNamedCasts = false; if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S, - &SS, DefaultValidator)) { + &SS, *CCC)) { unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest; unsigned QualifiedDiag = diag::err_no_member_suggest; std::string CorrectedStr(Corrected.getAsString(getLangOpts())); @@ -675,11 +685,12 @@ Corrected: Diag(NameLoc, UnqualifiedDiag) << Name << CorrectedQuotedStr << FixItHint::CreateReplacement(NameLoc, CorrectedStr); - else + else // FIXME: is this even reachable? Test it. Diag(NameLoc, QualifiedDiag) << Name << computeDeclContext(SS, false) << CorrectedQuotedStr << SS.getRange() - << FixItHint::CreateReplacement(NameLoc, CorrectedStr); + << FixItHint::CreateReplacement(Corrected.getCorrectionRange(), + CorrectedStr); // Update the name, so that the caller has the new name. Name = Corrected.getCorrectionAsIdentifierInfo(); @@ -705,7 +716,7 @@ Corrected: if (ObjCIvarDecl *Ivar = Result.getAsSingle<ObjCIvarDecl>()) { Result.clear(); ExprResult E(LookupInObjCMethod(Result, S, Ivar->getIdentifier())); - return move(E); + return E; } goto Corrected; @@ -731,8 +742,9 @@ Corrected: // perform some heroics to see if we actually have a // template-argument-list, which would indicate a missing 'template' // keyword here. - return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(), - NameInfo, /*TemplateArgs=*/0); + return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(), + NameInfo, IsAddressOfOperand, + /*TemplateArgs=*/0); } case LookupResult::Found: @@ -808,14 +820,16 @@ Corrected: return NameClassification::TypeTemplate(Template); } } - + NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl(); if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) { DiagnoseUseOfDecl(Type, NameLoc); QualType T = Context.getTypeDeclType(Type); + if (SS.isNotEmpty()) + return buildNestedType(*this, SS, T, NameLoc); return ParsedType::make(T); } - + ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(FirstDecl); if (!Class) { // FIXME: It's unfortunate that we don't have a Type node for handling this. @@ -838,24 +852,28 @@ Corrected: return ParsedType::make(T); } + // We can have a type template here if we're classifying a template argument. + if (isa<TemplateDecl>(FirstDecl) && !isa<FunctionTemplateDecl>(FirstDecl)) + return NameClassification::TypeTemplate( + TemplateName(cast<TemplateDecl>(FirstDecl))); + // 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. - if (!getLangOpts().ObjC1 && FirstDecl && !isa<ClassTemplateDecl>(FirstDecl) && - !isa<TypeAliasTemplateDecl>(FirstDecl)) { + if (!getLangOpts().ObjC1) { bool NextIsOp = NextToken.is(tok::amp) || NextToken.is(tok::star); if ((NextToken.is(tok::identifier) || (NextIsOp && FirstDecl->isFunctionOrFunctionTemplate())) && isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) { - FirstDecl = (*Result.begin())->getUnderlyingDecl(); - if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) { - DiagnoseUseOfDecl(Type, NameLoc); - QualType T = Context.getTypeDeclType(Type); - return ParsedType::make(T); - } + TypeDecl *Type = Result.getAsSingle<TypeDecl>(); + DiagnoseUseOfDecl(Type, NameLoc); + QualType T = Context.getTypeDeclType(Type); + if (SS.isNotEmpty()) + return buildNestedType(*this, SS, T, NameLoc); + return ParsedType::make(T); } } - if (!Result.empty() && (*Result.begin())->isCXXClassMember()) + if (FirstDecl->isCXXClassMember()) return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, 0); bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren)); @@ -1186,8 +1204,14 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { Context.DeclMustBeEmitted(FD)) return false; } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + // Don't warn on variables of const-qualified or reference type, since their + // values can be used even if though they're not odr-used, and because const + // qualified variables can appear in headers in contexts where they're not + // intended to be used. + // FIXME: Use more principled rules for these exemptions. if (!VD->isFileVarDecl() || - VD->getType().isConstant(Context) || + VD->getType().isConstQualified() || + VD->getType()->isReferenceType() || Context.DeclMustBeEmitted(VD)) return false; @@ -1248,7 +1272,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { QualType Ty = VD->getType(); // Only look at the outermost level of typedef. - if (const TypedefType *TT = dyn_cast<TypedefType>(Ty)) { + if (const TypedefType *TT = Ty->getAs<TypedefType>()) { if (TT->getDecl()->hasAttr<UnusedAttr>()) return false; } @@ -1268,6 +1292,8 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { return false; if (const Expr *Init = VD->getInit()) { + if (const ExprWithCleanups *Cleanups = dyn_cast<ExprWithCleanups>(Init)) + Init = Cleanups->getSubExpr(); const CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init); if (Construct && !Construct->isElidable()) { @@ -1706,6 +1732,25 @@ DeclHasAttr(const Decl *D, const Attr *A) { if (AA) return false; + // The following thread safety attributes can also be duplicated. + switch (A->getKind()) { + case attr::ExclusiveLocksRequired: + case attr::SharedLocksRequired: + case attr::LocksExcluded: + case attr::ExclusiveLockFunction: + case attr::SharedLockFunction: + case attr::UnlockFunction: + case attr::ExclusiveTrylockFunction: + case attr::SharedTrylockFunction: + case attr::GuardedBy: + case attr::PtGuardedBy: + case attr::AcquiredBefore: + case attr::AcquiredAfter: + return false; + default: + ; + } + const OwnershipAttr *OA = dyn_cast<OwnershipAttr>(A); const AnnotateAttr *Ann = dyn_cast<AnnotateAttr>(A); for (Decl::attr_iterator i = D->attr_begin(), e = D->attr_end(); i != e; ++i) @@ -1908,6 +1953,19 @@ static bool canRedefineFunction(const FunctionDecl *FD, FD->getStorageClass() == SC_Extern); } +/// Is the given calling convention the ABI default for the given +/// declaration? +static bool isABIDefaultCC(Sema &S, CallingConv CC, FunctionDecl *D) { + CallingConv ABIDefaultCC; + if (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance()) { + ABIDefaultCC = S.Context.getDefaultCXXMethodCallConv(D->isVariadic()); + } else { + // Free C function or a static method. + ABIDefaultCC = (S.Context.getLangOpts().MRTD ? CC_X86StdCall : CC_C); + } + return ABIDefaultCC == CC; +} + /// MergeFunctionDecl - We just parsed a function 'New' from /// declarator D which has the same name and scope as a previous /// declaration 'Old'. Figure out how to resolve this situation, @@ -1976,6 +2034,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { // later declared or defined without one, the second decl assumes the // calling convention of the first. // + // It's OK if a function is first declared without a calling convention, + // but is later declared or defined with the default calling convention. + // // For the new decl, we have to look at the NON-canonical type to tell the // difference between a function that really doesn't have a calling // convention and one that is declared cdecl. That's because in @@ -1989,10 +2050,22 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); bool RequiresAdjustment = false; - if (OldTypeInfo.getCC() != CC_Default && - NewTypeInfo.getCC() == CC_Default) { + if (OldTypeInfo.getCC() == NewTypeInfo.getCC()) { + // Fast path: nothing to do. + + // Inherit the CC from the previous declaration if it was specified + // there but not here. + } else if (NewTypeInfo.getCC() == CC_Default) { NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); RequiresAdjustment = true; + + // Don't complain about mismatches when the default CC is + // effectively the same as the explict one. + } else if (OldTypeInfo.getCC() == CC_Default && + isABIDefaultCC(*this, NewTypeInfo.getCC(), New)) { + NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); + RequiresAdjustment = true; + } else if (!Context.isSameCallConv(OldTypeInfo.getCC(), NewTypeInfo.getCC())) { // Calling conventions really aren't compatible, so complain. @@ -2398,7 +2471,7 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) { } if (MergedT.isNull()) { Diag(New->getLocation(), diag::err_redefinition_different_type) - << New->getDeclName(); + << New->getDeclName() << New->getType() << Old->getType(); Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); } @@ -2551,8 +2624,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { /// no declarator (e.g. "struct foo;") is parsed. Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS) { - return ParsedFreeStandingDeclSpec(S, AS, DS, - MultiTemplateParamsArg(*this, 0, 0)); + return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg()); } /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with @@ -2565,6 +2637,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, TagDecl *Tag = 0; if (DS.getTypeSpecType() == DeclSpec::TST_class || DS.getTypeSpecType() == DeclSpec::TST_struct || + DS.getTypeSpecType() == DeclSpec::TST_interface || DS.getTypeSpecType() == DeclSpec::TST_union || DS.getTypeSpecType() == DeclSpec::TST_enum) { TagD = DS.getRepAsDecl(); @@ -2603,7 +2676,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag) << (DS.getTypeSpecType() == DeclSpec::TST_class ? 0 : DS.getTypeSpecType() == DeclSpec::TST_struct ? 1 : - DS.getTypeSpecType() == DeclSpec::TST_union ? 2 : 3); + DS.getTypeSpecType() == DeclSpec::TST_interface ? 2 : + DS.getTypeSpecType() == DeclSpec::TST_union ? 3 : 4); else Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_no_declarators); // Don't emit warnings after this error. @@ -2724,16 +2798,17 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec::TST TypeSpecType = DS.getTypeSpecType(); if (TypeSpecType == DeclSpec::TST_class || TypeSpecType == DeclSpec::TST_struct || + TypeSpecType == DeclSpec::TST_interface || TypeSpecType == DeclSpec::TST_union || TypeSpecType == DeclSpec::TST_enum) { AttributeList* attrs = DS.getAttributes().getList(); while (attrs) { - Diag(attrs->getScopeLoc(), - diag::warn_declspec_attribute_ignored) + Diag(attrs->getLoc(), diag::warn_declspec_attribute_ignored) << attrs->getName() << (TypeSpecType == DeclSpec::TST_class ? 0 : TypeSpecType == DeclSpec::TST_struct ? 1 : - TypeSpecType == DeclSpec::TST_union ? 2 : 3); + TypeSpecType == DeclSpec::TST_union ? 2 : + TypeSpecType == DeclSpec::TST_interface ? 3 : 4); attrs = attrs->getNext(); } } @@ -3353,7 +3428,6 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, switch (DS.getTypeSpecType()) { case DeclSpec::TST_typename: case DeclSpec::TST_typeofType: - case DeclSpec::TST_decltype: case DeclSpec::TST_underlyingType: case DeclSpec::TST_atomic: { // Grab the type from the parser. @@ -3377,6 +3451,7 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, break; } + case DeclSpec::TST_decltype: case DeclSpec::TST_typeofExpr: { Expr *E = DS.getRepAsExpr(); ExprResult Result = S.RebuildExprInCurrentInstantiation(E); @@ -3411,7 +3486,7 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { D.setFunctionDefinitionKind(FDK_Declaration); - Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg(*this)); + Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg()); if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer() && Dcl && Dcl->getDeclContext()->isFileContext()) @@ -3476,7 +3551,8 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, // void X::f(); // }; if (Cur->Equals(DC)) { - Diag(Loc, diag::warn_member_extra_qualification) + Diag(Loc, LangOpts.MicrosoftExt? diag::warn_member_extra_qualification + : diag::err_member_extra_qualification) << Name << FixItHint::CreateRemoval(SS.getRange()); SS.clear(); return false; @@ -3710,11 +3786,11 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, New = ActOnTypedefDeclarator(S, D, DC, TInfo, Previous); } else if (R->isFunctionType()) { New = ActOnFunctionDeclarator(S, D, DC, TInfo, Previous, - move(TemplateParamLists), + TemplateParamLists, AddToScope); } else { New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous, - move(TemplateParamLists)); + TemplateParamLists); } if (New == 0) @@ -3729,9 +3805,9 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, return New; } -/// TryToFixInvalidVariablyModifiedType - Helper method to turn variable array -/// types into constant array types in certain situations which would otherwise -/// be errors (for GCC compatibility). +/// Helper method to turn variable array types into constant array +/// types in certain situations which would otherwise be errors (for +/// GCC compatibility). static QualType TryToFixInvalidVariablyModifiedType(QualType T, ASTContext &Context, bool &SizeIsNegative, @@ -3799,6 +3875,52 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T, Res, ArrayType::Normal, 0); } +static void +FixInvalidVariablyModifiedTypeLoc(TypeLoc SrcTL, TypeLoc DstTL) { + if (PointerTypeLoc* SrcPTL = dyn_cast<PointerTypeLoc>(&SrcTL)) { + PointerTypeLoc* DstPTL = cast<PointerTypeLoc>(&DstTL); + FixInvalidVariablyModifiedTypeLoc(SrcPTL->getPointeeLoc(), + DstPTL->getPointeeLoc()); + DstPTL->setStarLoc(SrcPTL->getStarLoc()); + return; + } + if (ParenTypeLoc* SrcPTL = dyn_cast<ParenTypeLoc>(&SrcTL)) { + ParenTypeLoc* DstPTL = cast<ParenTypeLoc>(&DstTL); + FixInvalidVariablyModifiedTypeLoc(SrcPTL->getInnerLoc(), + DstPTL->getInnerLoc()); + DstPTL->setLParenLoc(SrcPTL->getLParenLoc()); + DstPTL->setRParenLoc(SrcPTL->getRParenLoc()); + return; + } + ArrayTypeLoc* SrcATL = cast<ArrayTypeLoc>(&SrcTL); + ArrayTypeLoc* DstATL = cast<ArrayTypeLoc>(&DstTL); + TypeLoc SrcElemTL = SrcATL->getElementLoc(); + TypeLoc DstElemTL = DstATL->getElementLoc(); + DstElemTL.initializeFullCopy(SrcElemTL); + DstATL->setLBracketLoc(SrcATL->getLBracketLoc()); + DstATL->setSizeExpr(SrcATL->getSizeExpr()); + DstATL->setRBracketLoc(SrcATL->getRBracketLoc()); +} + +/// Helper method to turn variable array types into constant array +/// types in certain situations which would otherwise be errors (for +/// GCC compatibility). +static TypeSourceInfo* +TryToFixInvalidVariablyModifiedTypeSourceInfo(TypeSourceInfo *TInfo, + ASTContext &Context, + bool &SizeIsNegative, + llvm::APSInt &Oversized) { + QualType FixedTy + = TryToFixInvalidVariablyModifiedType(TInfo->getType(), Context, + SizeIsNegative, Oversized); + if (FixedTy.isNull()) + return 0; + TypeSourceInfo *FixedTInfo = Context.getTrivialTypeSourceInfo(FixedTy); + FixInvalidVariablyModifiedTypeLoc(TInfo->getTypeLoc(), + FixedTInfo->getTypeLoc()); + return FixedTInfo; +} + /// \brief Register the given locally-scoped external C declaration so /// that it can be found later for redeclarations void @@ -3926,19 +4048,21 @@ Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) { // then it shall have block scope. // Note that variably modified types must be fixed before merging the decl so // that redeclarations will match. - QualType T = NewTD->getUnderlyingType(); + TypeSourceInfo *TInfo = NewTD->getTypeSourceInfo(); + QualType T = TInfo->getType(); if (T->isVariablyModifiedType()) { getCurFunction()->setHasBranchProtectedScope(); if (S->getFnParent() == 0) { bool SizeIsNegative; llvm::APSInt Oversized; - QualType FixedTy = - TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative, - Oversized); - if (!FixedTy.isNull()) { + TypeSourceInfo *FixedTInfo = + TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context, + SizeIsNegative, + Oversized); + if (FixedTInfo) { Diag(NewTD->getLocation(), diag::warn_illegal_constant_array_size); - NewTD->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(FixedTy)); + NewTD->setTypeSourceInfo(FixedTInfo); } else { if (SizeIsNegative) Diag(NewTD->getLocation(), diag::err_typecheck_negative_array_size); @@ -4203,7 +4327,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, D.getDeclSpec().getLocStart(), D.getIdentifierLoc(), D.getCXXScopeSpec(), - TemplateParamLists.get(), + TemplateParamLists.data(), TemplateParamLists.size(), /*never a friend*/ false, isExplicitSpecialization, @@ -4244,7 +4368,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (TemplateParamLists.size() > 0 && D.getCXXScopeSpec().isSet()) { NewVD->setTemplateParameterListsInfo(Context, TemplateParamLists.size(), - TemplateParamLists.release()); + TemplateParamLists.data()); } if (D.getDeclSpec().isConstexprSpecified()) @@ -4281,6 +4405,14 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewVD, D); + if (getLangOpts().CUDA) { + // CUDA B.2.5: "__shared__ and __constant__ variables have implied static + // storage [duration]." + if (SC == SC_None && S->getFnParent() != 0 && + (NewVD->hasAttr<CUDASharedAttr>() || NewVD->hasAttr<CUDAConstantAttr>())) + NewVD->setStorageClass(SC_Static); + } + // In auto-retain/release, infer strong retension for variables of // retainable type. if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(NewVD)) @@ -4490,7 +4622,8 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, if (NewVD->isInvalidDecl()) return false; - QualType T = NewVD->getType(); + TypeSourceInfo *TInfo = NewVD->getTypeSourceInfo(); + QualType T = TInfo->getType(); if (T->isObjCObjectType()) { Diag(NewVD->getLocation(), diag::err_statically_allocated_object) @@ -4522,8 +4655,10 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, && !NewVD->hasAttr<BlocksAttr>()) { if (getLangOpts().getGC() != LangOptions::NonGC) Diag(NewVD->getLocation(), diag::warn_gc_attribute_weak_on_local); - else + else { + assert(!getLangOpts().ObjCAutoRefCount); Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local); + } } bool isVM = T->isVariablyModifiedType(); @@ -4535,11 +4670,10 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, (T->isVariableArrayType() && NewVD->hasGlobalStorage())) { bool SizeIsNegative; llvm::APSInt Oversized; - QualType FixedTy = - TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative, - Oversized); - - if (FixedTy.isNull() && T->isVariableArrayType()) { + TypeSourceInfo *FixedTInfo = + TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context, + SizeIsNegative, Oversized); + if (FixedTInfo == 0 && T->isVariableArrayType()) { const VariableArrayType *VAT = Context.getAsVariableArrayType(T); // FIXME: This won't give the correct result for // int a[10][n]; @@ -4558,7 +4692,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, return false; } - if (FixedTy.isNull()) { + if (FixedTInfo == 0) { if (NewVD->isFileVarDecl()) Diag(NewVD->getLocation(), diag::err_vm_decl_in_file_scope); else @@ -4568,7 +4702,8 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, } Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size); - NewVD->setType(FixedTy); + NewVD->setType(FixedTInfo->getType()); + NewVD->setTypeSourceInfo(FixedTInfo); } if (Previous.empty() && NewVD->isExternC()) { @@ -4655,6 +4790,31 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier, return false; } +namespace { + enum OverrideErrorKind { OEK_All, OEK_NonDeleted, OEK_Deleted }; +} +/// \brief Report an error regarding overriding, along with any relevant +/// overriden methods. +/// +/// \param DiagID the primary error to report. +/// \param MD the overriding method. +/// \param OEK which overrides to include as notes. +static void ReportOverrides(Sema& S, unsigned DiagID, const CXXMethodDecl *MD, + OverrideErrorKind OEK = OEK_All) { + S.Diag(MD->getLocation(), DiagID) << MD->getDeclName(); + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); + I != E; ++I) { + // This check (& the OEK parameter) could be replaced by a predicate, but + // without lambdas that would be overkill. This is still nicer than writing + // out the diag loop 3 times. + if ((OEK == OEK_All) || + (OEK == OEK_NonDeleted && !(*I)->isDeleted()) || + (OEK == OEK_Deleted && (*I)->isDeleted())) + S.Diag((*I)->getLocation(), diag::note_overridden_virtual_function); + } +} + /// AddOverriddenMethods - See if a method overrides any in the base classes, /// and if so, check that it's a valid override and remember it. bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { @@ -4663,6 +4823,8 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { FindOverriddenMethodData Data; Data.Method = MD; Data.S = this; + bool hasDeletedOverridenMethods = false; + bool hasNonDeletedOverridenMethods = false; bool AddedAny = false; if (DC->lookupInBases(&FindOverriddenMethod, &Data, Paths)) { for (CXXBasePaths::decl_iterator I = Paths.found_decls_begin(), @@ -4672,12 +4834,21 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { if (!CheckOverridingFunctionReturnType(MD, OldMD) && !CheckOverridingFunctionExceptionSpec(MD, OldMD) && !CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) { + hasDeletedOverridenMethods |= OldMD->isDeleted(); + hasNonDeletedOverridenMethods |= !OldMD->isDeleted(); AddedAny = true; } } } } - + + if (hasDeletedOverridenMethods && !MD->isDeleted()) { + ReportOverrides(*this, diag::err_non_deleted_override, MD, OEK_Deleted); + } + if (hasNonDeletedOverridenMethods && MD->isDeleted()) { + ReportOverrides(*this, diag::err_deleted_override, MD, OEK_NonDeleted); + } + return AddedAny; } @@ -4837,6 +5008,10 @@ static NamedDecl* DiagnoseInvalidRedeclaration( } if (Correction) { + // FIXME: use Correction.getCorrectionRange() instead of computing the range + // here. This requires passing in the CXXScopeSpec to CorrectTypo which in + // turn causes the correction to fully qualify the name. If we fix + // CorrectTypo to minimally qualify then this change should be good. SourceRange FixItLoc(NewFD->getLocation()); CXXScopeSpec &SS = ExtraArgs.D.getCXXScopeSpec(); if (Correction.getCorrectionSpecifier() && SS.isValid()) @@ -5072,6 +5247,22 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, } } +void Sema::checkVoidParamDecl(ParmVarDecl *Param) { + // In C++, the empty parameter-type-list must be spelled "void"; a + // typedef of void is not permitted. + if (getLangOpts().CPlusPlus && + Param->getType().getUnqualifiedType() != Context.VoidTy) { + bool IsTypeAlias = false; + if (const TypedefType *TT = Param->getType()->getAs<TypedefType>()) + IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl()); + else if (const TemplateSpecializationType *TST = + Param->getType()->getAs<TemplateSpecializationType>()) + IsTypeAlias = TST->isTypeAlias(); + Diag(Param->getLocation(), diag::err_param_typedef_of_void) + << IsTypeAlias; + } +} + NamedDecl* Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, @@ -5138,6 +5329,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setImplicitlyInline(); } + // If this is a method defined in an __interface, and is not a constructor + // or an overloaded operator, then set the pure flag (isVirtual will already + // return true). + if (const CXXRecordDecl *Parent = + dyn_cast<CXXRecordDecl>(NewFD->getDeclContext())) { + if (Parent->isInterface() && cast<CXXMethodDecl>(NewFD)->isUserProvided()) + NewFD->setPure(true); + } + SetNestedNameSpecifier(NewFD, D); isExplicitSpecialization = false; isFunctionTemplateSpecialization = false; @@ -5157,7 +5357,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, D.getDeclSpec().getLocStart(), D.getIdentifierLoc(), D.getCXXScopeSpec(), - TemplateParamLists.get(), + TemplateParamLists.data(), TemplateParamLists.size(), isFriend, isExplicitSpecialization, @@ -5196,7 +5396,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (TemplateParamLists.size() > 1) { NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists.size() - 1, - TemplateParamLists.release()); + TemplateParamLists.data()); } } else { // This is a function template specialization. @@ -5204,7 +5404,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // For source fidelity, store all the template param lists. NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists.size(), - TemplateParamLists.release()); + TemplateParamLists.data()); // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);". if (isFriend) { @@ -5236,7 +5436,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // For source fidelity, store all the template param lists. NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists.size(), - TemplateParamLists.release()); + TemplateParamLists.data()); } if (Invalid) { @@ -5376,6 +5576,20 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, diag::err_static_out_of_line) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } + + // C++11 [except.spec]p15: + // A deallocation function with no exception-specification is treated + // as if it were specified with noexcept(true). + const FunctionProtoType *FPT = R->getAs<FunctionProtoType>(); + if ((Name.getCXXOverloadedOperator() == OO_Delete || + Name.getCXXOverloadedOperator() == OO_Array_Delete) && + getLangOpts().CPlusPlus0x && FPT && !FPT->hasExceptionSpec()) { + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.ExceptionSpecType = EST_BasicNoexcept; + NewFD->setType(Context.getFunctionType(FPT->getResultType(), + FPT->arg_type_begin(), + FPT->getNumArgs(), EPI)); + } } // Filter out previous declarations that don't match the scope. @@ -5413,21 +5627,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, FTI.ArgInfo[0].Param && cast<ParmVarDecl>(FTI.ArgInfo[0].Param)->getType()->isVoidType()) { // Empty arg list, don't push any params. - ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[0].Param); - - // In C++, the empty parameter-type-list must be spelled "void"; a - // typedef of void is not permitted. - if (getLangOpts().CPlusPlus && - Param->getType().getUnqualifiedType() != Context.VoidTy) { - bool IsTypeAlias = false; - if (const TypedefType *TT = Param->getType()->getAs<TypedefType>()) - IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl()); - else if (const TemplateSpecializationType *TST = - Param->getType()->getAs<TemplateSpecializationType>()) - IsTypeAlias = TST->isTypeAlias(); - Diag(Param->getLocation(), diag::err_param_typedef_of_void) - << IsTypeAlias; - } + checkVoidParamDecl(cast<ParmVarDecl>(FTI.ArgInfo[0].Param)); } else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) { for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param); @@ -5500,6 +5700,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization)); } + // Make graceful recovery from an invalid redeclaration. + else if (!Previous.empty()) + D.setRedeclaration(true); assert((NewFD->isInvalidDecl() || !D.isRedeclaration() || Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); @@ -5510,12 +5713,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, TemplateIdAnnotation *TemplateId = D.getName().TemplateId; TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); - ASTTemplateArgsPtr TemplateArgsPtr(*this, - TemplateId->getTemplateArgs(), + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); translateTemplateArguments(TemplateArgsPtr, TemplateArgs); - TemplateArgsPtr.release(); HasExplicitTemplateArgs = true; @@ -5969,20 +6170,12 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // Find any virtual functions that this function overrides. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD)) { if (!Method->isFunctionTemplateSpecialization() && - !Method->getDescribedFunctionTemplate()) { + !Method->getDescribedFunctionTemplate() && + Method->isCanonicalDecl()) { if (AddOverriddenMethods(Method->getParent(), Method)) { // If the function was marked as "static", we have a problem. if (NewFD->getStorageClass() == SC_Static) { - Diag(NewFD->getLocation(), diag::err_static_overrides_virtual) - << NewFD->getDeclName(); - for (CXXMethodDecl::method_iterator - Overridden = Method->begin_overridden_methods(), - OverriddenEnd = Method->end_overridden_methods(); - Overridden != OverriddenEnd; - ++Overridden) { - Diag((*Overridden)->getLocation(), - diag::note_overridden_virtual_function); - } + ReportOverrides(*this, diag::err_static_overrides_virtual, Method); } } } @@ -6191,28 +6384,12 @@ namespace { } } - // Sometimes, the expression passed in lacks the casts that are used - // to determine which DeclRefExpr's to check. Assume that the casts - // are present and continue visiting the expression. - void HandleExpr(Expr *E) { - // Skip checking T a = a where T is not a record or reference type. - // Doing so is a way to silence uninitialized warnings. - if (isRecordType || isReferenceType) - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) - HandleDeclRefExpr(DRE); - - if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { - HandleValue(CO->getTrueExpr()); - HandleValue(CO->getFalseExpr()); - } - - Visit(E); - } - // For most expressions, the cast is directly above the DeclRefExpr. // For conditional operators, the cast can be outside the conditional // operator if both expressions are DeclRefExpr's. void HandleValue(Expr *E) { + if (isReferenceType) + return; E = E->IgnoreParenImpCasts(); if (DeclRefExpr* DRE = dyn_cast<DeclRefExpr>(E)) { HandleDeclRefExpr(DRE); @@ -6222,11 +6399,32 @@ namespace { if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { HandleValue(CO->getTrueExpr()); HandleValue(CO->getFalseExpr()); + return; + } + + if (isa<MemberExpr>(E)) { + Expr *Base = E->IgnoreParenImpCasts(); + while (MemberExpr *ME = dyn_cast<MemberExpr>(Base)) { + // Check for static member variables and don't warn on them. + if (!isa<FieldDecl>(ME->getMemberDecl())) + return; + Base = ME->getBase()->IgnoreParenImpCasts(); + } + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) + HandleDeclRefExpr(DRE); + return; } } + // Reference types are handled here since all uses of references are + // bad, not just r-value uses. + void VisitDeclRefExpr(DeclRefExpr *E) { + if (isReferenceType) + HandleDeclRefExpr(E); + } + void VisitImplicitCastExpr(ImplicitCastExpr *E) { - if ((!isRecordType && E->getCastKind() == CK_LValueToRValue) || + if (E->getCastKind() == CK_LValueToRValue || (isRecordType && E->getCastKind() == CK_NoOp)) HandleValue(E->getSubExpr()); @@ -6237,22 +6435,36 @@ namespace { // Don't warn on arrays since they can be treated as pointers. if (E->getType()->canDecayToPointerType()) return; - ValueDecl *VD = E->getMemberDecl(); - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(VD); - if (isa<FieldDecl>(VD) || (MD && !MD->isStatic())) - if (DeclRefExpr *DRE - = dyn_cast<DeclRefExpr>(E->getBase()->IgnoreParenImpCasts())) { + // Warn when a non-static method call is followed by non-static member + // field accesses, which is followed by a DeclRefExpr. + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(E->getMemberDecl()); + bool Warn = (MD && !MD->isStatic()); + Expr *Base = E->getBase()->IgnoreParenImpCasts(); + while (MemberExpr *ME = dyn_cast<MemberExpr>(Base)) { + if (!isa<FieldDecl>(ME->getMemberDecl())) + Warn = false; + Base = ME->getBase()->IgnoreParenImpCasts(); + } + + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) { + if (Warn) HandleDeclRefExpr(DRE); - return; - } + return; + } - Inherited::VisitMemberExpr(E); + // The base of a MemberExpr is not a MemberExpr or a DeclRefExpr. + // Visit that expression. + Visit(Base); } void VisitUnaryOperator(UnaryOperator *E) { // For POD record types, addresses of its own members are well-defined. - if (E->getOpcode() == UO_AddrOf && isRecordType && isPODType && - isa<MemberExpr>(E->getSubExpr()->IgnoreParens())) return; + if (E->getOpcode() == UO_AddrOf && isRecordType && + isa<MemberExpr>(E->getSubExpr()->IgnoreParens())) { + if (!isPODType) + HandleValue(E->getSubExpr()); + return; + } Inherited::VisitUnaryOperator(E); } @@ -6261,20 +6473,38 @@ namespace { void HandleDeclRefExpr(DeclRefExpr *DRE) { Decl* ReferenceDecl = DRE->getDecl(); if (OrigDecl != ReferenceDecl) return; - LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName, - Sema::NotForRedeclaration); + unsigned diag = isReferenceType + ? diag::warn_uninit_self_reference_in_reference_init + : diag::warn_uninit_self_reference_in_init; S.DiagRuntimeBehavior(DRE->getLocStart(), DRE, - S.PDiag(diag::warn_uninit_self_reference_in_init) - << Result.getLookupName() + S.PDiag(diag) + << DRE->getNameInfo().getName() << OrigDecl->getLocation() << DRE->getSourceRange()); } }; -} -/// CheckSelfReference - Warns if OrigDecl is used in expression E. -void Sema::CheckSelfReference(Decl* OrigDecl, Expr *E) { - SelfReferenceChecker(*this, OrigDecl).HandleExpr(E); + /// CheckSelfReference - Warns if OrigDecl is used in expression E. + static void CheckSelfReference(Sema &S, Decl* OrigDecl, Expr *E, + bool DirectInit) { + // Parameters arguments are occassionially constructed with itself, + // for instance, in recursive functions. Skip them. + if (isa<ParmVarDecl>(OrigDecl)) + return; + + E = E->IgnoreParens(); + + // Skip checking T a = a where T is not a record or reference type. + // Doing so is a way to silence uninitialized warnings. + if (!DirectInit && !cast<VarDecl>(OrigDecl)->getType()->isRecordType()) + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) + if (ICE->getCastKind() == CK_LValueToRValue) + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr())) + if (DRE->getDecl() == OrigDecl) + return; + + SelfReferenceChecker(S, OrigDecl).Visit(E); + } } /// AddInitializerToDecl - Adds the initializer Init to the @@ -6311,15 +6541,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, return; } - // Check for self-references within variable initializers. - // Variables declared within a function/method body (except for references) - // are handled by a dataflow analysis. - // Record types initialized by initializer list are handled here. - // Initialization by constructors are handled in TryConstructorInitialization. - if ((!VDecl->hasLocalStorage() || VDecl->getType()->isReferenceType()) && - (isa<InitListExpr>(Init) || !VDecl->getType()->isRecordType())) - CheckSelfReference(RealDecl, Init); - ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init); // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. @@ -6495,8 +6716,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, } InitializationSequence InitSeq(*this, Entity, Kind, Args, NumArgs); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, Args,NumArgs), - &DclT); + MultiExprArg(Args, NumArgs), &DclT); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; @@ -6505,6 +6725,14 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, Init = Result.takeAs<Expr>(); } + // Check for self-references within variable initializers. + // Variables declared within a function/method body (except for references) + // are handled by a dataflow analysis. + if (!VDecl->hasLocalStorage() || VDecl->getType()->isRecordType() || + VDecl->getType()->isReferenceType()) { + CheckSelfReference(*this, RealDecl, Init, DirectInit); + } + // If the type changed, it means we had an incomplete type that was // completed by the initializer. For example: // int ary[] = { 1, 3, 5 }; @@ -6515,9 +6743,28 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // Check any implicit conversions within the expression. CheckImplicitConversions(Init, VDecl->getLocation()); - if (!VDecl->isInvalidDecl()) + if (!VDecl->isInvalidDecl()) { checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init); + if (VDecl->hasAttr<BlocksAttr>()) + checkRetainCycles(VDecl, Init); + + // It is safe to assign a weak reference into a strong variable. + // Although this code can still have problems: + // id x = self.weakProp; + // id y = self.weakProp; + // we do not warn to warn spuriously when 'x' and 'y' are on separate + // paths through the function. This should be revisited if + // -Wrepeated-use-of-weak is made flow-sensitive. + if (VDecl->getType().getObjCLifetime() == Qualifiers::OCL_Strong) { + DiagnosticsEngine::Level Level = + Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, + Init->getLocStart()); + if (Level != DiagnosticsEngine::Ignored) + getCurFunction()->markSafeWeakUse(Init); + } + } + Init = MaybeCreateExprWithCleanups(Init); // Attach the initializer to the decl. VDecl->setInit(Init); @@ -6758,8 +7005,10 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, AbstractVariableType)) Var->setInvalidDecl(); if (!Type->isDependentType() && !Var->isInvalidDecl() && - Var->getStorageClass() == SC_PrivateExtern) + Var->getStorageClass() == SC_PrivateExtern) { Diag(Var->getLocation(), diag::warn_private_extern); + Diag(Var->getLocation(), diag::note_private_extern); + } return; @@ -6881,8 +7130,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, = InitializationKind::CreateDefault(Var->getLocation()); InitializationSequence InitSeq(*this, Entity, Kind, 0, 0); - ExprResult Init = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, 0, 0)); + ExprResult Init = InitSeq.Perform(*this, Entity, Kind, MultiExprArg()); if (Init.isInvalid()) Var->setInvalidDecl(); else if (Init.get()) { @@ -6957,11 +7205,22 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { } } + if (var->isThisDeclarationADefinition() && + var->getLinkage() == ExternalLinkage) { + // Find a previous declaration that's not a definition. + VarDecl *prev = var->getPreviousDecl(); + while (prev && prev->isThisDeclarationADefinition()) + prev = prev->getPreviousDecl(); + + if (!prev) + Diag(var->getLocation(), diag::warn_missing_variable_declarations) << var; + } + // All the following checks are C++ only. if (!getLangOpts().CPlusPlus) return; - QualType baseType = Context.getBaseElementType(var->getType()); - if (baseType->isDependentType()) return; + QualType type = var->getType(); + if (type->isDependentType()) return; // __block variables might require us to capture a copy-initializer. if (var->hasAttr<BlocksAttr>()) { @@ -6970,8 +7229,6 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { // Regardless, we don't want to ignore array nesting when // constructing this copy. - QualType type = var->getType(); - if (type->isStructureOrClassType()) { SourceLocation poi = var->getLocation(); Expr *varRef =new (Context) DeclRefExpr(var, false, type, VK_LValue, poi); @@ -6989,8 +7246,10 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { Expr *Init = var->getInit(); bool IsGlobal = var->hasGlobalStorage() && !var->isStaticLocal(); + QualType baseType = Context.getBaseElementType(type); - if (!var->getDeclContext()->isDependentContext() && Init) { + if (!var->getDeclContext()->isDependentContext() && + Init && !Init->isValueDependent()) { if (IsGlobal && !var->isConstexpr() && getDiagnostics().getDiagnosticLevel(diag::warn_global_constructor, var->getLocation()) @@ -7178,7 +7437,7 @@ void Sema::ActOnDocumentableDecls(Decl **Group, unsigned NumDecls) { // the lookahead in the lexer: we've consumed the semicolon and looked // ahead through comments. for (unsigned i = 0; i != NumDecls; ++i) - Context.getCommentForDecl(Group[i]); + Context.getCommentForDecl(Group[i], &PP); } } @@ -7450,6 +7709,9 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, unsigned DiagID; // unused DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc, PrevSpec, DiagID); + // Use the identifier location for the type source range. + DS.SetRangeStart(FTI.ArgInfo[i].IdentLoc); + DS.SetRangeEnd(FTI.ArgInfo[i].IdentLoc); Declarator ParamD(DS, Declarator::KNRTypeListContext); ParamD.SetIdentifier(FTI.ArgInfo[i].Ident, FTI.ArgInfo[i].IdentLoc); FTI.ArgInfo[i].Param = ActOnParamDeclarator(S, ParamD); @@ -7464,8 +7726,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { Scope *ParentScope = FnBodyScope->getParent(); D.setFunctionDefinitionKind(FDK_Definition); - Decl *DP = HandleDeclarator(ParentScope, D, - MultiTemplateParamsArg(*this)); + Decl *DP = HandleDeclarator(ParentScope, D, MultiTemplateParamsArg()); return ActOnStartOfFunctionDef(FnBodyScope, DP); } @@ -7707,7 +7968,7 @@ void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) { } Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) { - return ActOnFinishFunctionBody(D, move(BodyArg), false); + return ActOnFinishFunctionBody(D, BodyArg, false); } Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, @@ -7765,22 +8026,16 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (Body) computeNRVO(Body, getCurFunction()); } - if (getCurFunction()->ObjCShouldCallSuperDealloc) { - Diag(MD->getLocEnd(), diag::warn_objc_missing_super_dealloc); - getCurFunction()->ObjCShouldCallSuperDealloc = false; - } - if (getCurFunction()->ObjCShouldCallSuperFinalize) { - Diag(MD->getLocEnd(), diag::warn_objc_missing_super_finalize); - getCurFunction()->ObjCShouldCallSuperFinalize = false; + if (getCurFunction()->ObjCShouldCallSuper) { + Diag(MD->getLocEnd(), diag::warn_objc_missing_super_call) + << MD->getSelector().getAsString(); + getCurFunction()->ObjCShouldCallSuper = false; } } else { return 0; } - assert(!getCurFunction()->ObjCShouldCallSuperDealloc && - "This should only be set for ObjC methods, which should have been " - "handled in the block above."); - assert(!getCurFunction()->ObjCShouldCallSuperFinalize && + assert(!getCurFunction()->ObjCShouldCallSuper && "This should only be set for ObjC methods, which should have been " "handled in the block above."); @@ -7916,13 +8171,28 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy, DiagID); (void)Error; // Silence warning. assert(!Error && "Error setting up implicit decl!"); + SourceLocation NoLoc; Declarator D(DS, Declarator::BlockContext); - D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, false, - SourceLocation(), 0, 0, 0, true, - SourceLocation(), SourceLocation(), - SourceLocation(), SourceLocation(), - EST_None, SourceLocation(), - 0, 0, 0, 0, Loc, Loc, D), + D.AddTypeInfo(DeclaratorChunk::getFunction(/*HasProto=*/false, + /*IsAmbiguous=*/false, + /*RParenLoc=*/NoLoc, + /*ArgInfo=*/0, + /*NumArgs=*/0, + /*EllipsisLoc=*/NoLoc, + /*RParenLoc=*/NoLoc, + /*TypeQuals=*/0, + /*RefQualifierIsLvalueRef=*/true, + /*RefQualifierLoc=*/NoLoc, + /*ConstQualifierLoc=*/NoLoc, + /*VolatileQualifierLoc=*/NoLoc, + /*MutableLoc=*/NoLoc, + EST_None, + /*ESpecLoc=*/NoLoc, + /*Exceptions=*/0, + /*ExceptionRanges=*/0, + /*NumExceptions=*/0, + /*NoexceptExpr=*/0, + Loc, Loc, D), DS.getAttributes(), SourceLocation()); D.SetIdentifier(&II, Loc); @@ -8071,6 +8341,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, switch (D.getDeclSpec().getTypeSpecType()) { case TST_enum: case TST_struct: + case TST_interface: case TST_union: case TST_class: { TagDecl *tagFromDeclSpec = cast<TagDecl>(D.getDeclSpec().getRepAsDecl()); @@ -8146,6 +8417,29 @@ bool Sema::CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped, return false; } +/// \brief Get diagnostic %select index for tag kind for +/// redeclaration diagnostic message. +/// WARNING: Indexes apply to particular diagnostics only! +/// +/// \returns diagnostic %select index. +static unsigned getRedeclDiagFromTagKind(TagTypeKind Tag) { + switch (Tag) { + case TTK_Struct: return 0; + case TTK_Interface: return 1; + case TTK_Class: return 2; + default: llvm_unreachable("Invalid tag kind for redecl diagnostic!"); + } +} + +/// \brief Determine if tag kind is a class-key compatible with +/// class for redeclaration (class, struct, or __interface). +/// +/// \returns true iff the tag kind is compatible. +static bool isClassCompatTagKind(TagTypeKind Tag) +{ + return Tag == TTK_Struct || Tag == TTK_Class || Tag == TTK_Interface; +} + /// \brief Determine whether a tag with a given kind is acceptable /// as a redeclaration of the given tag declaration. /// @@ -8168,12 +8462,11 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, // struct class-key shall be used to refer to a class (clause 9) // declared using the class or struct class-key. TagTypeKind OldTag = Previous->getTagKind(); - if (!isDefinition || (NewTag != TTK_Class && NewTag != TTK_Struct)) + if (!isDefinition || !isClassCompatTagKind(NewTag)) if (OldTag == NewTag) return true; - if ((OldTag == TTK_Struct || OldTag == TTK_Class) && - (NewTag == TTK_Struct || NewTag == TTK_Class)) { + if (isClassCompatTagKind(OldTag) && isClassCompatTagKind(NewTag)) { // Warn about the struct/class tag mismatch. bool isTemplate = false; if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous)) @@ -8183,7 +8476,8 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, // In a template instantiation, do not offer fix-its for tag mismatches // since they usually mess up the template instead of fixing the problem. Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) - << (NewTag == TTK_Class) << isTemplate << &Name; + << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name + << getRedeclDiagFromTagKind(OldTag); return true; } @@ -8202,13 +8496,13 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, if (!previousMismatch) { previousMismatch = true; Diag(NewTagLoc, diag::warn_struct_class_previous_tag_mismatch) - << (NewTag == TTK_Class) << isTemplate << &Name; + << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name + << getRedeclDiagFromTagKind(I->getTagKind()); } Diag(I->getInnerLocStart(), diag::note_struct_class_suggestion) - << (NewTag == TTK_Class) + << getRedeclDiagFromTagKind(NewTag) << FixItHint::CreateReplacement(I->getInnerLocStart(), - NewTag == TTK_Class? - "class" : "struct"); + TypeWithKeyword::getTagTypeKindName(NewTag)); } } return true; @@ -8224,16 +8518,16 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, } Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) - << (NewTag == TTK_Class) - << isTemplate << &Name; + << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name + << getRedeclDiagFromTagKind(OldTag); Diag(Redecl->getLocation(), diag::note_previous_use); // If there is a previous defintion, suggest a fix-it. if (Previous->getDefinition()) { Diag(NewTagLoc, diag::note_struct_class_suggestion) - << (Redecl->getTagKind() == TTK_Class) + << getRedeclDiagFromTagKind(Redecl->getTagKind()) << FixItHint::CreateReplacement(SourceRange(NewTagLoc), - Redecl->getTagKind() == TTK_Class? "class" : "struct"); + TypeWithKeyword::getTagTypeKindName(Redecl->getTagKind())); } return true; @@ -8276,7 +8570,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, (SS.isNotEmpty() && TUK != TUK_Reference)) { if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier(KWLoc, NameLoc, SS, - TemplateParameterLists.get(), + TemplateParameterLists.data(), TemplateParameterLists.size(), TUK == TUK_Friend, isExplicitSpecialization, @@ -8293,8 +8587,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SS, Name, NameLoc, Attr, TemplateParams, AS, ModulePrivateLoc, - TemplateParameterLists.size() - 1, - (TemplateParameterList**) TemplateParameterLists.release()); + TemplateParameterLists.size()-1, + TemplateParameterLists.data()); return Result.get(); } else { // The "template<>" header is extraneous. @@ -8843,7 +9137,7 @@ CreateNewDecl: if (TemplateParameterLists.size() > 0) { New->setTemplateParameterListsInfo(Context, TemplateParameterLists.size(), - (TemplateParameterList**) TemplateParameterLists.release()); + TemplateParameterLists.data()); } } else @@ -9298,12 +9592,15 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, if (!InvalidDecl && T->isVariablyModifiedType()) { bool SizeIsNegative; llvm::APSInt Oversized; - QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context, - SizeIsNegative, - Oversized); - if (!FixedTy.isNull()) { + + TypeSourceInfo *FixedTInfo = + TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context, + SizeIsNegative, + Oversized); + if (FixedTInfo) { Diag(Loc, diag::warn_illegal_constant_array_size); - T = FixedTy; + TInfo = FixedTInfo; + T = FixedTInfo->getType(); } else { if (SizeIsNegative) Diag(Loc, diag::err_typecheck_negative_array_size); @@ -9460,12 +9757,12 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) { return false; } -/// If the given constructor is user-provided, produce a diagnostic explaining +/// If the given constructor is user-declared, produce a diagnostic explaining /// that it makes the class non-trivial. -static bool DiagnoseNontrivialUserProvidedCtor(Sema &S, QualType QT, +static bool diagnoseNonTrivialUserDeclaredCtor(Sema &S, QualType QT, CXXConstructorDecl *CD, Sema::CXXSpecialMember CSM) { - if (!CD->isUserProvided()) + if (CD->isImplicit()) return false; SourceLocation CtorLoc = CD->getLocation(); @@ -9488,17 +9785,17 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { if (RD->hasUserDeclaredConstructor()) { typedef CXXRecordDecl::ctor_iterator ctor_iter; for (ctor_iter CI = RD->ctor_begin(), CE = RD->ctor_end(); CI != CE; ++CI) - if (DiagnoseNontrivialUserProvidedCtor(*this, QT, *CI, member)) + if (diagnoseNonTrivialUserDeclaredCtor(*this, QT, *CI, member)) return; - // No user-provided constructors; look for constructor templates. + // No user-delcared constructors; look for constructor templates. typedef CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl> tmpl_iter; for (tmpl_iter TI(RD->decls_begin()), TE(RD->decls_end()); TI != TE; ++TI) { CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(TI->getTemplatedDecl()); - if (CD && DiagnoseNontrivialUserProvidedCtor(*this, QT, CD, member)) + if (CD && diagnoseNonTrivialUserDeclaredCtor(*this, QT, CD, member)) return; } } @@ -10025,42 +10322,6 @@ void Sema::ActOnFields(Scope* S, Convs->setAccess(I, (*I)->getAccess()); if (!CXXRecord->isDependentType()) { - // Objective-C Automatic Reference Counting: - // If a class has a non-static data member of Objective-C pointer - // type (or array thereof), it is a non-POD type and its - // default constructor (if any), copy constructor, copy assignment - // operator, and destructor are non-trivial. - // - // This rule is also handled by CXXRecordDecl::completeDefinition(). - // However, here we check whether this particular class is only - // non-POD because of the presence of an Objective-C pointer member. - // If so, objects of this type cannot be shared between code compiled - // with ARC and code compiled with manual retain/release. - if (getLangOpts().ObjCAutoRefCount && - CXXRecord->hasObjectMember() && - CXXRecord->getLinkage() == ExternalLinkage) { - if (CXXRecord->isPOD()) { - Diag(CXXRecord->getLocation(), - diag::warn_arc_non_pod_class_with_object_member) - << CXXRecord; - } else { - // FIXME: Fix-Its would be nice here, but finding a good location - // for them is going to be tricky. - if (CXXRecord->hasTrivialCopyConstructor()) - Diag(CXXRecord->getLocation(), - diag::warn_arc_trivial_member_function_with_object_member) - << CXXRecord << 0; - if (CXXRecord->hasTrivialCopyAssignment()) - Diag(CXXRecord->getLocation(), - diag::warn_arc_trivial_member_function_with_object_member) - << CXXRecord << 1; - if (CXXRecord->hasTrivialDestructor()) - Diag(CXXRecord->getLocation(), - diag::warn_arc_trivial_member_function_with_object_member) - << CXXRecord << 2; - } - } - // Adjust user-defined destructor exception spec. if (getLangOpts().CPlusPlus0x && CXXRecord->hasUserDeclaredDestructor()) @@ -10092,7 +10353,7 @@ void Sema::ActOnFields(Scope* S, // class subobject has more than one final overrider the // program is ill-formed. Diag(Record->getLocation(), diag::err_multiple_final_overriders) - << (NamedDecl *)M->first << Record; + << (const NamedDecl *)M->first << Record; Diag(M->first->getLocation(), diag::note_overridden_virtual_function); for (OverridingMethods::overriding_iterator @@ -10100,7 +10361,7 @@ void Sema::ActOnFields(Scope* S, OMEnd = SO->second.end(); OM != OMEnd; ++OM) Diag(OM->Method->getLocation(), diag::note_final_overrider) - << (NamedDecl *)M->first << OM->Method->getParent(); + << (const NamedDecl *)M->first << OM->Method->getParent(); Record->setInvalidDecl(); } @@ -10461,57 +10722,6 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, return New; } -// Emits a warning if every element in the enum is the same value and if -// every element is initialized with a integer or boolean literal. -static void CheckForUniqueEnumValues(Sema &S, Decl **Elements, - unsigned NumElements, EnumDecl *Enum, - QualType EnumType) { - if (S.Diags.getDiagnosticLevel(diag::warn_identical_enum_values, - Enum->getLocation()) == - DiagnosticsEngine::Ignored) - return; - - if (NumElements < 2) - return; - - if (!Enum->getIdentifier()) - return; - - llvm::APSInt FirstVal; - - for (unsigned i = 0; i != NumElements; ++i) { - EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]); - if (!ECD) - return; - - Expr *InitExpr = ECD->getInitExpr(); - if (!InitExpr) - return; - InitExpr = InitExpr->IgnoreImpCasts(); - if (!isa<IntegerLiteral>(InitExpr) && !isa<CXXBoolLiteralExpr>(InitExpr)) - return; - - if (i == 0) { - FirstVal = ECD->getInitVal(); - continue; - } - - if (!llvm::APSInt::isSameValue(FirstVal, ECD->getInitVal())) - return; - } - - S.Diag(Enum->getLocation(), diag::warn_identical_enum_values) - << EnumType << FirstVal.toString(10) - << Enum->getSourceRange(); - - EnumConstantDecl *Last = cast<EnumConstantDecl>(Elements[NumElements - 1]), - *Next = cast<EnumConstantDecl>(Elements[NumElements - 2]); - - S.Diag(Last->getLocation(), diag::note_identical_enum_values) - << FixItHint::CreateReplacement(Last->getInitExpr()->getSourceRange(), - Next->getName()); -} - void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, SourceLocation RBraceLoc, Decl *EnumDeclX, Decl **Elements, unsigned NumElements, @@ -10734,8 +10944,6 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // it needs to go into the function scope. if (InFunctionDeclarator) DeclsInPrototypeScope.push_back(Enum); - - CheckForUniqueEnumValues(*this, Elements, NumElements, Enum, EnumType); } Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr, @@ -10834,10 +11042,6 @@ Decl *Sema::getObjCDeclContext() const { } AvailabilityResult Sema::getCurContextAvailability() const { - const Decl *D = cast<Decl>(getCurLexicalContext()); - // A category implicitly has the availability of the interface. - if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D)) - D = CatD->getClassInterface(); - + const Decl *D = cast<Decl>(getCurObjCLexicalContext()); return D->getAvailability(); } |