diff options
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 2809 |
1 files changed, 1823 insertions, 986 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index f5e045a722a0..dd30c1261ed7 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -26,6 +26,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" +#include "clang/AST/CharUnits.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Parse/ParseDiagnostic.h" @@ -59,7 +60,7 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr) { /// and then return NULL. ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec *SS, - bool isClassName, + bool isClassName, bool HasTrailingDot, ParsedType ObjectTypePtr) { // Determine where we will perform name lookup. DeclContext *LookupCtx = 0; @@ -192,13 +193,15 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, T = getElaboratedType(ETK_None, *SS, T); } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) { - T = Context.getObjCInterfaceType(IDecl); - } else { + if (!HasTrailingDot) + T = Context.getObjCInterfaceType(IDecl); + } + + if (T.isNull()) { // If it's not plausibly a type, suppress diagnostics. Result.suppressDiagnostics(); return ParsedType(); } - return ParsedType::make(T); } @@ -544,7 +547,9 @@ static bool IsDisallowedCopyOrAssign(const CXXMethodDecl *D) { if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D)) return CD->isCopyConstructor(); - return D->isCopyAssignment(); + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) + return Method->isCopyAssignmentOperator(); + return false; } bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { @@ -554,11 +559,8 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { return false; // Ignore class templates. - if (D->getDeclContext()->isDependentContext()) - return false; - - // We warn for unused decls internal to the translation unit. - if (D->getLinkage() == ExternalLinkage) + if (D->getDeclContext()->isDependentContext() || + D->getLexicalDeclContext()->isDependentContext()) return false; if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { @@ -575,25 +577,32 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { return false; } - if (FD->isThisDeclarationADefinition()) - return !Context.DeclMustBeEmitted(FD); - return true; - } + if (FD->isThisDeclarationADefinition() && + Context.DeclMustBeEmitted(FD)) + return false; + + } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (!VD->isFileVarDecl() || + VD->getType().isConstant(Context) || + Context.DeclMustBeEmitted(VD)) + return false; - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (VD->isStaticDataMember() && VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return false; - if ( VD->isFileVarDecl() && - !VD->getType().isConstant(Context)) - return !Context.DeclMustBeEmitted(VD); + } else { + return false; } - return false; - } + // Only warn for unused decls internal to the translation unit. + if (D->getLinkage() == ExternalLinkage) + return false; + + return true; +} - void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) { +void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) { if (!D) return; @@ -620,6 +629,9 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { if (D->isUsed() || D->hasAttr<UnusedAttr>()) return false; + if (isa<LabelDecl>(D)) + return true; + // White-list anything that isn't a local variable. if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) || !D->getDeclContext()->isFunctionOrMethod()) @@ -662,16 +674,29 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { return true; } +/// DiagnoseUnusedDecl - Emit warnings about declarations that are not used +/// unless they are marked attr(unused). void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { if (!ShouldDiagnoseUnusedDecl(D)) return; + unsigned DiagID; if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable()) - Diag(D->getLocation(), diag::warn_unused_exception_param) - << D->getDeclName(); + DiagID = diag::warn_unused_exception_param; + else if (isa<LabelDecl>(D)) + DiagID = diag::warn_unused_label; else - Diag(D->getLocation(), diag::warn_unused_variable) - << D->getDeclName(); + DiagID = diag::warn_unused_variable; + + Diag(D->getLocation(), DiagID) << D->getDeclName(); +} + +static void CheckPoppedLabel(LabelDecl *L, Sema &S) { + // Verify that we have no forward references left. If so, there was a goto + // or address of a label taken, but no definition of it. Label fwd + // definitions are indicated with a null substmt. + if (L->getStmt() == 0) + S.Diag(L->getLocation(), diag::err_undeclared_label_use) <<L->getDeclName(); } void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { @@ -690,9 +715,13 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (!D->getDeclName()) continue; // Diagnose unused variables in this scope. - if (S->getNumErrorsAtStart() == getDiagnostics().getNumErrors()) + if (!S->hasErrorOccurred()) DiagnoseUnusedDecl(D); + // If this was a forward reference to a label, verify it was defined. + if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) + CheckPoppedLabel(LD, *this); + // Remove this name from our lexical scope. IdResolver.RemoveDecl(D); } @@ -769,17 +798,6 @@ Scope *Sema::getNonFieldDeclScope(Scope *S) { return S; } -void Sema::InitBuiltinVaListType() { - if (!Context.getBuiltinVaListType().isNull()) - return; - - IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list"); - NamedDecl *VaDecl = LookupSingleName(TUScope, VaIdent, SourceLocation(), - LookupOrdinaryName, ForRedeclaration); - TypedefDecl *VaTypedef = cast<TypedefDecl>(VaDecl); - Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef)); -} - /// LazilyCreateBuiltin - The specified Builtin-ID was first used at /// file scope. lazily create a decl for it. ForRedeclaration is true /// if we're creating this built-in in anticipation of redeclaring the @@ -789,9 +807,6 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, SourceLocation Loc) { Builtin::ID BID = (Builtin::ID)bid; - if (Context.BuiltinInfo.hasVAListUse(BID)) - InitBuiltinVaListType(); - ASTContext::GetBuiltinTypeError Error; QualType R = Context.GetBuiltinType(BID, Error); switch (Error) { @@ -801,13 +816,13 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, case ASTContext::GE_Missing_stdio: if (ForRedeclaration) - Diag(Loc, diag::err_implicit_decl_requires_stdio) + Diag(Loc, diag::warn_implicit_decl_requires_stdio) << Context.BuiltinInfo.GetName(BID); return 0; case ASTContext::GE_Missing_setjmp: if (ForRedeclaration) - Diag(Loc, diag::err_implicit_decl_requires_setjmp) + Diag(Loc, diag::warn_implicit_decl_requires_setjmp) << Context.BuiltinInfo.GetName(BID); return 0; } @@ -817,7 +832,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, << Context.BuiltinInfo.GetName(BID) << R; if (Context.BuiltinInfo.getHeaderName(BID) && - Diags.getDiagnosticLevel(diag::ext_implicit_lib_function_decl) + Diags.getDiagnosticLevel(diag::ext_implicit_lib_function_decl, Loc) != Diagnostic::Ignored) Diag(Loc, diag::note_please_include_header) << Context.BuiltinInfo.getHeaderName(BID) @@ -834,7 +849,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, // Create Decl objects for each parameter, adding them to the // FunctionDecl. - if (FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) { + if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) { llvm::SmallVector<ParmVarDecl*, 16> Params; for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0, @@ -1026,11 +1041,11 @@ static void MergeDeclAttributes(Decl *New, Decl *Old, ASTContext &C) { // we process them. if (!New->hasAttrs()) New->setAttrs(AttrVec()); - for (Decl::attr_iterator i = Old->attr_begin(), e = Old->attr_end(); i != e; - ++i) { - // FIXME: Make this more general than just checking for Overloadable. - if (!DeclHasAttr(New, *i) && (*i)->getKind() != attr::Overloadable) { - Attr *NewAttr = (*i)->clone(C); + for (specific_attr_iterator<InheritableAttr> + i = Old->specific_attr_begin<InheritableAttr>(), + e = Old->specific_attr_end<InheritableAttr>(); i != e; ++i) { + if (!DeclHasAttr(New, *i)) { + InheritableAttr *NewAttr = cast<InheritableAttr>((*i)->clone(C)); NewAttr->setInherited(true); New->addAttr(NewAttr); } @@ -1061,7 +1076,8 @@ Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) { if (isa<CXXDestructorDecl>(MD)) return Sema::CXXDestructor; - assert(MD->isCopyAssignment() && "Must have copy assignment operator"); + assert(MD->isCopyAssignmentOperator() && + "Must have copy assignment operator"); return Sema::CXXCopyAssignment; } @@ -1147,15 +1163,15 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // // Note also that we DO NOT return at this point, because we still have // other tests to run. - const FunctionType *OldType = OldQType->getAs<FunctionType>(); + const FunctionType *OldType = cast<FunctionType>(OldQType); const FunctionType *NewType = New->getType()->getAs<FunctionType>(); - const FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); - const FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); + FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); + FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); + bool RequiresAdjustment = false; if (OldTypeInfo.getCC() != CC_Default && NewTypeInfo.getCC() == CC_Default) { - NewQType = Context.getCallConvType(NewQType, OldTypeInfo.getCC()); - New->setType(NewQType); - NewQType = Context.getCanonicalType(NewQType); + NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); + RequiresAdjustment = true; } else if (!Context.isSameCallConv(OldTypeInfo.getCC(), NewTypeInfo.getCC())) { // Calling conventions really aren't compatible, so complain. @@ -1169,25 +1185,29 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { } // FIXME: diagnose the other way around? - if (OldType->getNoReturnAttr() && !NewType->getNoReturnAttr()) { - NewQType = Context.getNoReturnType(NewQType); - New->setType(NewQType); - assert(NewQType.isCanonical()); + if (OldTypeInfo.getNoReturn() && !NewTypeInfo.getNoReturn()) { + NewTypeInfo = NewTypeInfo.withNoReturn(true); + RequiresAdjustment = true; } // Merge regparm attribute. - if (OldType->getRegParmType() != NewType->getRegParmType()) { - if (NewType->getRegParmType()) { + if (OldTypeInfo.getRegParm() != NewTypeInfo.getRegParm()) { + if (NewTypeInfo.getRegParm()) { Diag(New->getLocation(), diag::err_regparm_mismatch) << NewType->getRegParmType() << OldType->getRegParmType(); Diag(Old->getLocation(), diag::note_previous_declaration); return true; } - - NewQType = Context.getRegParmType(NewQType, OldType->getRegParmType()); - New->setType(NewQType); - assert(NewQType.isCanonical()); + + NewTypeInfo = NewTypeInfo.withRegParm(OldTypeInfo.getRegParm()); + RequiresAdjustment = true; + } + + if (RequiresAdjustment) { + NewType = Context.adjustFunctionType(NewType, NewTypeInfo); + New->setType(QualType(NewType, 0)); + NewQType = Context.getCanonicalType(New->getType()); } if (getLangOptions().CPlusPlus) { @@ -1195,17 +1215,19 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // Certain function declarations cannot be overloaded: // -- Function declarations that differ only in the return type // cannot be overloaded. - QualType OldReturnType - = cast<FunctionType>(OldQType.getTypePtr())->getResultType(); - QualType NewReturnType - = cast<FunctionType>(NewQType.getTypePtr())->getResultType(); + QualType OldReturnType = OldType->getResultType(); + QualType NewReturnType = cast<FunctionType>(NewQType)->getResultType(); QualType ResQT; if (OldReturnType != NewReturnType) { if (NewReturnType->isObjCObjectPointerType() && OldReturnType->isObjCObjectPointerType()) ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType); if (ResQT.isNull()) { - Diag(New->getLocation(), diag::err_ovl_diff_return_type); + if (New->isCXXClassMember() && New->isOutOfLine()) + Diag(New->getLocation(), + diag::err_member_def_does_not_match_ret_type) << New; + else + Diag(New->getLocation(), diag::err_ovl_diff_return_type); Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); return true; } @@ -1268,9 +1290,19 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // (C++98 8.3.5p3): // All declarations for a function shall agree exactly in both the // return type and the parameter-type-list. - // attributes should be ignored when comparing. - if (Context.getNoReturnType(OldQType, false) == - Context.getNoReturnType(NewQType, false)) + // We also want to respect all the extended bits except noreturn. + + // noreturn should now match unless the old type info didn't have it. + QualType OldQTypeForComparison = OldQType; + if (!OldTypeInfo.getNoReturn() && NewTypeInfo.getNoReturn()) { + assert(OldQType == QualType(OldType, 0)); + const FunctionType *OldTypeForComparison + = Context.adjustFunctionType(OldType, OldTypeInfo.withNoReturn(true)); + OldQTypeForComparison = QualType(OldTypeForComparison, 0); + assert(OldQTypeForComparison.isCanonical()); + } + + if (OldQTypeForComparison == NewQType) return MergeCompatibleFunctionDecls(New, Old); // Fall through for conflicting redeclarations and redefinitions. @@ -1292,10 +1324,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { OldProto->arg_type_end()); NewQType = Context.getFunctionType(NewFuncType->getResultType(), ParamTypes.data(), ParamTypes.size(), - OldProto->isVariadic(), - OldProto->getTypeQuals(), - false, false, 0, 0, - OldProto->getExtInfo()); + OldProto->getExtProtoInfo()); New->setType(NewQType); New->setHasInheritedPrototype(); @@ -1377,9 +1406,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { New->setType(Context.getFunctionType(MergedReturn, &ArgTypes[0], ArgTypes.size(), - OldProto->isVariadic(), 0, - false, false, 0, 0, - OldProto->getExtInfo())); + OldProto->getExtProtoInfo())); return MergeCompatibleFunctionDecls(New, Old); } @@ -1444,48 +1471,26 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { return false; } -/// MergeVarDecl - We just parsed a variable 'New' which has the same name -/// and scope as a previous declaration 'Old'. Figure out how to resolve this -/// situation, merging decls or emitting diagnostics as appropriate. +/// MergeVarDecl - We parsed a variable 'New' which has the same name and scope +/// as a previous declaration 'Old'. Figure out how to merge their types, +/// emitting diagnostics as appropriate. /// -/// Tentative definition rules (C99 6.9.2p2) are checked by -/// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative -/// definitions here, since the initializer hasn't been attached. +/// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back +/// to here in AddInitializerToDecl and AddCXXDirectInitializerToDecl. We can't +/// check them before the initializer is attached. /// -void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { - // If the new decl is already invalid, don't do any other checking. - if (New->isInvalidDecl()) +void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) { + if (New->isInvalidDecl() || Old->isInvalidDecl()) return; - // Verify the old decl was also a variable. - VarDecl *Old = 0; - if (!Previous.isSingleResult() || - !(Old = dyn_cast<VarDecl>(Previous.getFoundDecl()))) { - Diag(New->getLocation(), diag::err_redefinition_different_kind) - << New->getDeclName(); - Diag(Previous.getRepresentativeDecl()->getLocation(), - diag::note_previous_definition); - return New->setInvalidDecl(); - } - - // C++ [class.mem]p1: - // A member shall not be declared twice in the member-specification [...] - // - // Here, we need only consider static data members. - if (Old->isStaticDataMember() && !New->isOutOfLine()) { - Diag(New->getLocation(), diag::err_duplicate_member) - << New->getIdentifier(); - Diag(Old->getLocation(), diag::note_previous_declaration); - New->setInvalidDecl(); - } - - MergeDeclAttributes(New, Old, Context); - - // Merge the types QualType MergedT; if (getLangOptions().CPlusPlus) { - if (Context.hasSameType(New->getType(), Old->getType())) - MergedT = New->getType(); + AutoType *AT = New->getType()->getContainedAutoType(); + if (AT && !AT->isDeduced()) { + // We don't know what the new type is until the initializer is attached. + return; + } else if (Context.hasSameType(New->getType(), Old->getType())) + return; // C++ [basic.link]p10: // [...] the types specified by all declarations referring to a given // object or function shall be identical, except that declarations for an @@ -1509,7 +1514,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { MergedT = Old->getType(); } else if (New->getType()->isObjCObjectPointerType() && Old->getType()->isObjCObjectPointerType()) { - MergedT = Context.mergeObjCGCQualifiers(New->getType(), Old->getType()); + MergedT = Context.mergeObjCGCQualifiers(New->getType(), + Old->getType()); } } else { MergedT = Context.mergeTypes(New->getType(), Old->getType()); @@ -1521,6 +1527,49 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { return New->setInvalidDecl(); } New->setType(MergedT); +} + +/// MergeVarDecl - We just parsed a variable 'New' which has the same name +/// and scope as a previous declaration 'Old'. Figure out how to resolve this +/// situation, merging decls or emitting diagnostics as appropriate. +/// +/// Tentative definition rules (C99 6.9.2p2) are checked by +/// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative +/// definitions here, since the initializer hasn't been attached. +/// +void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { + // If the new decl is already invalid, don't do any other checking. + if (New->isInvalidDecl()) + return; + + // Verify the old decl was also a variable. + VarDecl *Old = 0; + if (!Previous.isSingleResult() || + !(Old = dyn_cast<VarDecl>(Previous.getFoundDecl()))) { + Diag(New->getLocation(), diag::err_redefinition_different_kind) + << New->getDeclName(); + Diag(Previous.getRepresentativeDecl()->getLocation(), + diag::note_previous_definition); + return New->setInvalidDecl(); + } + + // C++ [class.mem]p1: + // A member shall not be declared twice in the member-specification [...] + // + // Here, we need only consider static data members. + if (Old->isStaticDataMember() && !New->isOutOfLine()) { + Diag(New->getLocation(), diag::err_duplicate_member) + << New->getIdentifier(); + Diag(Old->getLocation(), diag::note_previous_declaration); + New->setInvalidDecl(); + } + + MergeDeclAttributes(New, Old, Context); + + // Merge the types. + MergeVarDeclTypes(New, Old); + if (New->isInvalidDecl()) + return; // C99 6.2.2p4: Check if we have a static decl followed by a non-static. if (New->getStorageClass() == SC_Static && @@ -1547,6 +1596,20 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { return New->setInvalidDecl(); } + // Check if extern is followed by non-extern and vice-versa. + if (New->hasExternalStorage() && + !Old->hasLinkage() && Old->isLocalVarDecl()) { + Diag(New->getLocation(), diag::err_extern_non_extern) << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + return New->setInvalidDecl(); + } + if (Old->hasExternalStorage() && + !New->hasLinkage() && New->isLocalVarDecl()) { + Diag(New->getLocation(), diag::err_non_extern_extern) << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + return New->setInvalidDecl(); + } + // Variables with external linkage are analyzed in FinalizeDeclaratorGroup. // FIXME: The test for external storage here seems wrong? We still @@ -1602,7 +1665,6 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { /// no declarator (e.g. "struct foo;") is parsed. Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS) { - // FIXME: Error on auto/register at file scope // FIXME: Error on inline/virtual/explicit // FIXME: Warn on useless __thread // FIXME: Warn on useless const/volatile @@ -1635,15 +1697,15 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, } if (DS.isFriendSpecified()) { - // If we're dealing with a class template decl, assume that the - // template routines are handling it. - if (TagD && isa<ClassTemplateDecl>(TagD)) + // If we're dealing with a decl but not a TagDecl, assume that + // whatever routines created it handled the friendship aspect. + if (TagD && !Tag) return 0; return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0)); } if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) { - ProcessDeclAttributeList(S, Record, DS.getAttributes()); + ProcessDeclAttributeList(S, Record, DS.getAttributes().getList()); if (!Record->getDeclName() && Record->isDefinition() && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { @@ -1654,12 +1716,24 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators) << DS.getSourceRange(); } + } - // Microsoft allows unnamed struct/union fields. Don't complain - // about them. - // FIXME: Should we support Microsoft's extensions in this area? - if (Record->getDeclName() && getLangOptions().Microsoft) - return Tag; + // Check for Microsoft C extension: anonymous struct. + if (getLangOptions().Microsoft && !getLangOptions().CPlusPlus && + CurContext->isRecord() && + DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) { + // Handle 2 kinds of anonymous struct: + // struct STRUCT; + // and + // STRUCT_TYPE; <- where STRUCT_TYPE is a typedef struct. + RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag); + if ((Record && Record->getDeclName() && !Record->isDefinition()) || + (DS.getTypeSpecType() == DeclSpec::TST_typename && + DS.getRepAsType().get()->isStructureType())) { + Diag(DS.getSourceRange().getBegin(), diag::ext_ms_anonymous_struct) + << DS.getSourceRange(); + return BuildMicrosoftCAnonymousStruct(S, DS, Record); + } } if (getLangOptions().CPlusPlus && @@ -1688,6 +1762,25 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, return TagD; } +/// ActOnVlaStmt - This rouine if finds a vla expression in a decl spec. +/// builds a statement for it and returns it so it is evaluated. +StmtResult Sema::ActOnVlaStmt(const DeclSpec &DS) { + StmtResult R; + if (DS.getTypeSpecType() == DeclSpec::TST_typeofExpr) { + Expr *Exp = DS.getRepAsExpr(); + QualType Ty = Exp->getType(); + if (Ty->isPointerType()) { + do + Ty = Ty->getAs<PointerType>()->getPointeeType(); + while (Ty->isPointerType()); + } + if (Ty->isVariableArrayType()) { + R = ActOnExprStmt(MakeFullExpr(Exp)); + } + } + return R; +} + /// We are trying to inject an anonymous member into the given scope; /// check if there's an existing declaration that can't be overloaded. /// @@ -1707,11 +1800,10 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef, // Pick a representative declaration. NamedDecl *PrevDecl = R.getRepresentativeDecl()->getUnderlyingDecl(); - if (PrevDecl && Owner->isRecord()) { - RecordDecl *Record = cast<RecordDecl>(Owner); - if (!SemaRef.isDeclInScope(PrevDecl, Record, S)) - return false; - } + assert(PrevDecl && "Expected a non-null Decl"); + + if (!SemaRef.isDeclInScope(PrevDecl, Owner, S)) + return false; SemaRef.Diag(NameLoc, diagnostic) << Name; SemaRef.Diag(PrevDecl->getLocation(), diag::note_previous_declaration); @@ -1738,18 +1830,24 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef, static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, DeclContext *Owner, RecordDecl *AnonRecord, - AccessSpecifier AS) { + AccessSpecifier AS, + llvm::SmallVector<NamedDecl*, 2> &Chaining, + bool MSAnonStruct) { unsigned diagKind = AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl : diag::err_anonymous_struct_member_redecl; bool Invalid = false; - for (RecordDecl::field_iterator F = AnonRecord->field_begin(), - FEnd = AnonRecord->field_end(); - F != FEnd; ++F) { - if ((*F)->getDeclName()) { - if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, (*F)->getDeclName(), - (*F)->getLocation(), diagKind)) { + + // Look every FieldDecl and IndirectFieldDecl with a name. + for (RecordDecl::decl_iterator D = AnonRecord->decls_begin(), + DEnd = AnonRecord->decls_end(); + D != DEnd; ++D) { + if ((isa<FieldDecl>(*D) || isa<IndirectFieldDecl>(*D)) && + cast<NamedDecl>(*D)->getDeclName()) { + ValueDecl *VD = cast<ValueDecl>(*D); + if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, VD->getDeclName(), + VD->getLocation(), diagKind)) { // C++ [class.union]p2: // The names of the members of an anonymous union shall be // distinct from the names of any other entity in the @@ -1761,20 +1859,34 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, // definition, the members of the anonymous union are // considered to have been defined in the scope in which the // anonymous union is declared. - Owner->makeDeclVisibleInContext(*F); - S->AddDecl(*F); - SemaRef.IdResolver.AddDecl(*F); + unsigned OldChainingSize = Chaining.size(); + if (IndirectFieldDecl *IF = dyn_cast<IndirectFieldDecl>(VD)) + for (IndirectFieldDecl::chain_iterator PI = IF->chain_begin(), + PE = IF->chain_end(); PI != PE; ++PI) + Chaining.push_back(*PI); + else + Chaining.push_back(VD); + + assert(Chaining.size() >= 2); + NamedDecl **NamedChain = + new (SemaRef.Context)NamedDecl*[Chaining.size()]; + for (unsigned i = 0; i < Chaining.size(); i++) + NamedChain[i] = Chaining[i]; + + IndirectFieldDecl* IndirectField = + IndirectFieldDecl::Create(SemaRef.Context, Owner, VD->getLocation(), + VD->getIdentifier(), VD->getType(), + NamedChain, Chaining.size()); + + IndirectField->setAccess(AS); + IndirectField->setImplicit(); + SemaRef.PushOnScopeChains(IndirectField, S); // That includes picking up the appropriate access specifier. - if (AS != AS_none) (*F)->setAccess(AS); + if (AS != AS_none) IndirectField->setAccess(AS); + + Chaining.resize(OldChainingSize); } - } else if (const RecordType *InnerRecordType - = (*F)->getType()->getAs<RecordType>()) { - RecordDecl *InnerRecord = InnerRecordType->getDecl(); - if (InnerRecord->isAnonymousStructOrUnion()) - Invalid = Invalid || - InjectAnonymousStructOrUnionMembers(SemaRef, S, Owner, - InnerRecord, AS); } } @@ -1819,7 +1931,7 @@ StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec) { llvm_unreachable("unknown storage class specifier"); } -/// ActOnAnonymousStructOrUnion - Handle the declaration of an +/// BuildAnonymousStructOrUnion - Handle the declaration of an /// anonymous structure or union. Anonymous unions are a C++ feature /// (C++ [class.union]) and a GNU C extension; anonymous structures /// are a GNU C and GNU C++ extension. @@ -1852,7 +1964,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Recover by adding 'static'. DS.SetStorageClassSpec(DeclSpec::SCS_static, SourceLocation(), - PrevSpec, DiagID); + PrevSpec, DiagID, getLangOptions()); } // C++ [class.union]p3: // A storage class is not allowed in a declaration of an @@ -1865,7 +1977,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Recover by removing the storage specifier. DS.SetStorageClassSpec(DeclSpec::SCS_unspecified, SourceLocation(), - PrevSpec, DiagID); + PrevSpec, DiagID, getLangOptions()); } // C++ [class.union]p2: @@ -1898,10 +2010,16 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, } else if (RecordDecl *MemRecord = dyn_cast<RecordDecl>(*Mem)) { if (!MemRecord->isAnonymousStructOrUnion() && MemRecord->getDeclName()) { - // This is a nested type declaration. - Diag(MemRecord->getLocation(), diag::err_anonymous_record_with_type) - << (int)Record->isUnion(); - Invalid = true; + // Visual C++ allows type definition in anonymous struct or union. + if (getLangOptions().Microsoft) + Diag(MemRecord->getLocation(), diag::ext_anonymous_record_with_type) + << (int)Record->isUnion(); + else { + // This is a nested type declaration. + Diag(MemRecord->getLocation(), diag::err_anonymous_record_with_type) + << (int)Record->isUnion(); + Invalid = true; + } } } else if (isa<AccessSpecDecl>(*Mem)) { // Any access specifier is fine. @@ -1915,9 +2033,17 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, DK = diag::err_anonymous_record_with_function; else if (isa<VarDecl>(*Mem)) DK = diag::err_anonymous_record_with_static; - Diag((*Mem)->getLocation(), DK) + + // Visual C++ allows type definition in anonymous struct or union. + if (getLangOptions().Microsoft && + DK == diag::err_anonymous_record_with_type) + Diag((*Mem)->getLocation(), diag::ext_anonymous_record_with_type) << (int)Record->isUnion(); + else { + Diag((*Mem)->getLocation(), DK) + << (int)Record->isUnion(); Invalid = true; + } } } } @@ -1942,11 +2068,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, TInfo, /*BitWidth=*/0, /*Mutable=*/false); Anon->setAccess(AS); - if (getLangOptions().CPlusPlus) { + if (getLangOptions().CPlusPlus) FieldCollector->Add(cast<FieldDecl>(Anon)); - if (!cast<CXXRecordDecl>(Record)->isEmpty()) - cast<CXXRecordDecl>(OwningClass)->setEmpty(false); - } } else { DeclSpec::SCS SCSpec = DS.getStorageClassSpec(); assert(SCSpec != DeclSpec::SCS_typedef && @@ -1978,7 +2101,11 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Inject the members of the anonymous struct/union into the owning // context and into the identifier resolver chain for name lookup // purposes. - if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS)) + llvm::SmallVector<NamedDecl*, 2> Chain; + Chain.push_back(Anon); + + if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS, + Chain, false)) Invalid = true; // Mark this as an anonymous struct/union type. Note that we do not @@ -1995,6 +2122,57 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, return Anon; } +/// BuildMicrosoftCAnonymousStruct - Handle the declaration of an +/// Microsoft C anonymous structure. +/// Ref: http://msdn.microsoft.com/en-us/library/z2cx9y4f.aspx +/// Example: +/// +/// struct A { int a; }; +/// struct B { struct A; int b; }; +/// +/// void foo() { +/// B var; +/// var.a = 3; +/// } +/// +Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, + RecordDecl *Record) { + + // If there is no Record, get the record via the typedef. + if (!Record) + Record = DS.getRepAsType().get()->getAsStructureType()->getDecl(); + + // Mock up a declarator. + Declarator Dc(DS, Declarator::TypeNameContext); + TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S); + assert(TInfo && "couldn't build declarator info for anonymous struct"); + + // Create a declaration for this anonymous struct. + NamedDecl* Anon = FieldDecl::Create(Context, + cast<RecordDecl>(CurContext), + DS.getSourceRange().getBegin(), + /*IdentifierInfo=*/0, + Context.getTypeDeclType(Record), + TInfo, + /*BitWidth=*/0, /*Mutable=*/false); + Anon->setImplicit(); + + // Add the anonymous struct object to the current context. + CurContext->addDecl(Anon); + + // Inject the members of the anonymous struct into the current + // context and into the identifier resolver chain for name lookup + // purposes. + llvm::SmallVector<NamedDecl*, 2> Chain; + Chain.push_back(Anon); + + if (InjectAnonymousStructOrUnionMembers(*this, S, CurContext, + Record->getDefinition(), + AS_none, Chain, true)) + Anon->setInvalidDecl(); + + return Anon; +} /// GetNameForDeclarator - Determine the full declaration name for the /// given Declarator. @@ -2216,7 +2394,8 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, diag::err_declarator_need_ident) << D.getDeclSpec().getSourceRange() << D.getSourceRange(); return 0; - } + } else if (DiagnoseUnexpandedParameterPack(NameInfo, UPPC_DeclarationType)) + return 0; // The scope passed in may not be a decl scope. Zip up the scope tree until // we find one that is. @@ -2228,6 +2407,10 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, if (D.getCXXScopeSpec().isInvalid()) D.setInvalidType(); else if (D.getCXXScopeSpec().isSet()) { + if (DiagnoseUnexpandedParameterPack(D.getCXXScopeSpec(), + UPPC_DeclarationQualifier)) + return 0; + bool EnteringContext = !D.getDeclSpec().isFriendSpecified(); DC = computeDeclContext(D.getCXXScopeSpec(), EnteringContext); if (!DC) { @@ -2248,11 +2431,30 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, RequireCompleteDeclContext(D.getCXXScopeSpec(), DC)) return 0; - if (isa<CXXRecordDecl>(DC) && !cast<CXXRecordDecl>(DC)->hasDefinition()) { - Diag(D.getIdentifierLoc(), - diag::err_member_def_undefined_record) - << Name << DC << D.getCXXScopeSpec().getRange(); - D.setInvalidType(); + if (isa<CXXRecordDecl>(DC)) { + if (!cast<CXXRecordDecl>(DC)->hasDefinition()) { + Diag(D.getIdentifierLoc(), + diag::err_member_def_undefined_record) + << Name << DC << D.getCXXScopeSpec().getRange(); + D.setInvalidType(); + } else if (isa<CXXRecordDecl>(CurContext) && + !D.getDeclSpec().isFriendSpecified()) { + // The user provided a superfluous scope specifier inside a class + // definition: + // + // class X { + // void X::f(); + // }; + if (CurContext->Equals(DC)) + Diag(D.getIdentifierLoc(), diag::warn_member_extra_qualification) + << Name << FixItHint::CreateRemoval(D.getCXXScopeSpec().getRange()); + else + Diag(D.getIdentifierLoc(), diag::err_member_qualification) + << Name << D.getCXXScopeSpec().getRange(); + + // Pretend that this qualifier was not here. + D.getCXXScopeSpec().clear(); + } } // Check whether we need to rebuild the type of the given @@ -2264,12 +2466,33 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, D.setInvalidType(); } } - + + // C++ [class.mem]p13: + // If T is the name of a class, then each of the following shall have a + // name different from T: + // - every static data member of class T; + // - every member function of class T + // - every member of class T that is itself a type; + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) + if (Record->getIdentifier() && Record->getDeclName() == Name) { + Diag(D.getIdentifierLoc(), diag::err_member_name_of_class) + << Name; + + // If this is a typedef, we'll end up spewing multiple diagnostics. + // Just return early; it's safer. + if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) + return 0; + } + NamedDecl *New; TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType R = TInfo->getType(); + if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, + UPPC_DeclarationType)) + D.setInvalidType(); + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); @@ -2425,7 +2648,16 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T, Oversized); if (FixedType.isNull()) return FixedType; FixedType = Context.getPointerType(FixedType); - return Qs.apply(FixedType); + return Qs.apply(Context, FixedType); + } + if (const ParenType* PTy = dyn_cast<ParenType>(Ty)) { + QualType Inner = PTy->getInnerType(); + QualType FixedType = + TryToFixInvalidVariablyModifiedType(Inner, Context, SizeIsNegative, + Oversized); + if (FixedType.isNull()) return FixedType; + FixedType = Context.getParenType(FixedType); + return Qs.apply(Context, FixedType); } const VariableArrayType* VLATy = dyn_cast<VariableArrayType>(T); @@ -2595,6 +2827,8 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, Context.setjmp_bufDecl(NewTD); else if (II->isStr("sigjmp_buf")) Context.setsigjmp_bufDecl(NewTD); + else if (II->isStr("__builtin_va_list")) + Context.setBuiltinVaListType(Context.getTypedefType(NewTD)); } return NewTD; @@ -2666,7 +2900,7 @@ static void SetNestedNameSpecifier(DeclaratorDecl *DD, Declarator &D) { } NamedDecl* -Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, +Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, @@ -2715,73 +2949,99 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.setInvalidType(); } } - if (DC->isRecord() && !CurContext->isRecord()) { - // This is an out-of-line definition of a static data member. + + bool isExplicitSpecialization = false; + VarDecl *NewVD; + if (!getLangOptions().CPlusPlus) { + NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), + II, R, TInfo, SC, SCAsWritten); + + if (D.isInvalidType()) + NewVD->setInvalidDecl(); + } else { + if (DC->isRecord() && !CurContext->isRecord()) { + // This is an out-of-line definition of a static data member. + if (SC == SC_Static) { + Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::err_static_out_of_line) + << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); + } else if (SC == SC_None) + SC = SC_Static; + } if (SC == SC_Static) { - Diag(D.getDeclSpec().getStorageClassSpecLoc(), - diag::err_static_out_of_line) - << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); - } else if (SC == SC_None) - SC = SC_Static; - } - if (SC == SC_Static) { - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) { - if (RD->isLocalClass()) - Diag(D.getIdentifierLoc(), - diag::err_static_data_member_not_allowed_in_local_class) - << Name << RD->getDeclName(); + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) { + if (RD->isLocalClass()) + Diag(D.getIdentifierLoc(), + diag::err_static_data_member_not_allowed_in_local_class) + << Name << RD->getDeclName(); + + // C++ [class.union]p1: If a union contains a static data member, + // the program is ill-formed. + // + // We also disallow static data members in anonymous structs. + if (CurContext->isRecord() && (RD->isUnion() || !RD->getDeclName())) + Diag(D.getIdentifierLoc(), + diag::err_static_data_member_not_allowed_in_union_or_anon_struct) + << Name << RD->isUnion(); + } } - } - // Match up the template parameter lists with the scope specifier, then - // determine whether we have a template or a template specialization. - bool isExplicitSpecialization = false; - unsigned NumMatchedTemplateParamLists = TemplateParamLists.size(); - bool Invalid = false; - if (TemplateParameterList *TemplateParams + // Match up the template parameter lists with the scope specifier, then + // determine whether we have a template or a template specialization. + isExplicitSpecialization = false; + unsigned NumMatchedTemplateParamLists = TemplateParamLists.size(); + bool Invalid = false; + if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( - D.getDeclSpec().getSourceRange().getBegin(), + D.getDeclSpec().getSourceRange().getBegin(), D.getCXXScopeSpec(), - (TemplateParameterList**)TemplateParamLists.get(), - TemplateParamLists.size(), + TemplateParamLists.get(), + TemplateParamLists.size(), /*never a friend*/ false, isExplicitSpecialization, Invalid)) { - // All but one template parameter lists have been matching. - --NumMatchedTemplateParamLists; - - if (TemplateParams->size() > 0) { - // There is no such thing as a variable template. - Diag(D.getIdentifierLoc(), diag::err_template_variable) - << II - << SourceRange(TemplateParams->getTemplateLoc(), - TemplateParams->getRAngleLoc()); - return 0; - } else { - // There is an extraneous 'template<>' for this variable. Complain - // about it, but allow the declaration of the variable. - Diag(TemplateParams->getTemplateLoc(), - diag::err_template_variable_noparams) - << II - << SourceRange(TemplateParams->getTemplateLoc(), - TemplateParams->getRAngleLoc()); + // All but one template parameter lists have been matching. + --NumMatchedTemplateParamLists; + + if (TemplateParams->size() > 0) { + // There is no such thing as a variable template. + Diag(D.getIdentifierLoc(), diag::err_template_variable) + << II + << SourceRange(TemplateParams->getTemplateLoc(), + TemplateParams->getRAngleLoc()); + return 0; + } else { + // There is an extraneous 'template<>' for this variable. Complain + // about it, but allow the declaration of the variable. + Diag(TemplateParams->getTemplateLoc(), + diag::err_template_variable_noparams) + << II + << SourceRange(TemplateParams->getTemplateLoc(), + TemplateParams->getRAngleLoc()); - isExplicitSpecialization = true; + isExplicitSpecialization = true; + } } - } - VarDecl *NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), - II, R, TInfo, SC, SCAsWritten); + NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), + II, R, TInfo, SC, SCAsWritten); - if (D.isInvalidType() || Invalid) - NewVD->setInvalidDecl(); + // If this decl has an auto type in need of deduction, mark the VarDecl so + // we can diagnose uses of it in its own initializer. + if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto) { + NewVD->setParsingAutoInit(R->getContainedAutoType()); + } + + if (D.isInvalidType() || Invalid) + NewVD->setInvalidDecl(); - SetNestedNameSpecifier(NewVD, D); + SetNestedNameSpecifier(NewVD, D); - if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) { - NewVD->setTemplateParameterListsInfo(Context, - NumMatchedTemplateParamLists, - (TemplateParameterList**)TemplateParamLists.release()); + if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) { + NewVD->setTemplateParameterListsInfo(Context, + NumMatchedTemplateParamLists, + TemplateParamLists.release()); + } } if (D.getDeclSpec().isThreadSpecified()) { @@ -2801,11 +3061,29 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, ProcessDeclAttributes(S, NewVD, D); // Handle GNU asm-label extension (encoded as an attribute). - if (Expr *E = (Expr*) D.getAsmLabel()) { + if (Expr *E = (Expr*)D.getAsmLabel()) { // The parser guarantees this is a string. StringLiteral *SE = cast<StringLiteral>(E); - NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), - Context, SE->getString())); + llvm::StringRef Label = SE->getString(); + if (S->getFnParent() != 0) { + switch (SC) { + case SC_None: + case SC_Auto: + Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label; + break; + case SC_Register: + if (!Context.Target.isValidGCCRegisterName(Label)) + Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; + break; + case SC_Static: + case SC_Extern: + case SC_PrivateExtern: + break; + } + } + + NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), + Context, Label)); } // Diagnose shadowed variables before filtering for scope. @@ -2817,33 +3095,37 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, // declaration has linkage). FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage()); - // Merge the decl with the existing one if appropriate. - if (!Previous.empty()) { - if (Previous.isSingleResult() && - isa<FieldDecl>(Previous.getFoundDecl()) && - D.getCXXScopeSpec().isSet()) { - // The user tried to define a non-static data member - // out-of-line (C++ [dcl.meaning]p1). - Diag(NewVD->getLocation(), diag::err_nonstatic_member_out_of_line) + if (!getLangOptions().CPlusPlus) + CheckVariableDeclaration(NewVD, Previous, Redeclaration); + else { + // Merge the decl with the existing one if appropriate. + if (!Previous.empty()) { + if (Previous.isSingleResult() && + isa<FieldDecl>(Previous.getFoundDecl()) && + D.getCXXScopeSpec().isSet()) { + // The user tried to define a non-static data member + // out-of-line (C++ [dcl.meaning]p1). + Diag(NewVD->getLocation(), diag::err_nonstatic_member_out_of_line) + << D.getCXXScopeSpec().getRange(); + Previous.clear(); + NewVD->setInvalidDecl(); + } + } else if (D.getCXXScopeSpec().isSet()) { + // No previous declaration in the qualifying scope. + Diag(D.getIdentifierLoc(), diag::err_no_member) + << Name << computeDeclContext(D.getCXXScopeSpec(), true) << D.getCXXScopeSpec().getRange(); - Previous.clear(); NewVD->setInvalidDecl(); } - } else if (D.getCXXScopeSpec().isSet()) { - // No previous declaration in the qualifying scope. - Diag(D.getIdentifierLoc(), diag::err_no_member) - << Name << computeDeclContext(D.getCXXScopeSpec(), true) - << D.getCXXScopeSpec().getRange(); - NewVD->setInvalidDecl(); - } - - CheckVariableDeclaration(NewVD, Previous, Redeclaration); - // This is an explicit specialization of a static data member. Check it. - if (isExplicitSpecialization && !NewVD->isInvalidDecl() && - CheckMemberSpecialization(NewVD, Previous)) - NewVD->setInvalidDecl(); + CheckVariableDeclaration(NewVD, Previous, Redeclaration); + // This is an explicit specialization of a static data member. Check it. + if (isExplicitSpecialization && !NewVD->isInvalidDecl() && + CheckMemberSpecialization(NewVD, Previous)) + NewVD->setInvalidDecl(); + } + // attributes declared post-definition are currently ignored // FIXME: This should be handled in attribute merging, not // here. @@ -2866,7 +3148,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, // member, set the visibility of this variable. if (NewVD->getLinkage() == ExternalLinkage && !DC->isRecord()) AddPushedVisibilityAttribute(NewVD); - + MarkUnusedFileScopedDecl(NewVD); return NewVD; @@ -2883,13 +3165,13 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, /// void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { // Return if warning is ignored. - if (Diags.getDiagnosticLevel(diag::warn_decl_shadow) == Diagnostic::Ignored) + if (Diags.getDiagnosticLevel(diag::warn_decl_shadow, R.getNameLoc()) == + Diagnostic::Ignored) return; - // Don't diagnose declarations at file scope. The scope might not - // have a DeclContext if (e.g.) we're parsing a function prototype. - DeclContext *NewDC = static_cast<DeclContext*>(S->getEntity()); - if (NewDC && NewDC->isFileContext()) + // Don't diagnose declarations at file scope. + DeclContext *NewDC = D->getDeclContext(); + if (NewDC->isFileContext()) return; // Only diagnose if we're shadowing an unambiguous field or variable. @@ -2900,6 +3182,36 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { if (!isa<VarDecl>(ShadowedDecl) && !isa<FieldDecl>(ShadowedDecl)) return; + // Fields are not shadowed by variables in C++ static methods. + if (isa<FieldDecl>(ShadowedDecl)) + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewDC)) + if (MD->isStatic()) + return; + + if (VarDecl *shadowedVar = dyn_cast<VarDecl>(ShadowedDecl)) + if (shadowedVar->isExternC()) { + // Don't warn for this case: + // + // @code + // extern int bob; + // void f() { + // extern int bob; + // } + // @endcode + if (D->isExternC()) + return; + + // For shadowing external vars, make sure that we point to the global + // declaration, not a locally scoped extern declaration. + for (VarDecl::redecl_iterator + I = shadowedVar->redecls_begin(), E = shadowedVar->redecls_end(); + I != E; ++I) + if (I->isFileVarDecl()) { + ShadowedDecl = *I; + break; + } + } + DeclContext *OldDC = ShadowedDecl->getDeclContext(); // Only warn about certain kinds of shadowing for class members. @@ -2937,6 +3249,10 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { /// \brief Check -Wshadow without the advantage of a previous lookup. void Sema::CheckShadow(Scope *S, VarDecl *D) { + if (Diags.getDiagnosticLevel(diag::warn_decl_shadow, D->getLocation()) == + Diagnostic::Ignored) + return; + LookupResult R(*this, D->getDeclName(), D->getLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); LookupName(R, S); @@ -2971,7 +3287,7 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, // This includes arrays of objects with address space qualifiers, but not // automatic variables that point to other address spaces. // ISO/IEC TR 18037 S5.1.2 - if (NewVD->hasLocalStorage() && (T.getAddressSpace() != 0)) { + if (NewVD->hasLocalStorage() && T.getAddressSpace() != 0) { Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl); return NewVD->setInvalidDecl(); } @@ -2979,7 +3295,7 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, if (NewVD->hasLocalStorage() && T.isObjCGCWeak() && !NewVD->hasAttr<BlocksAttr>()) Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local); - + bool isVM = T->isVariablyModifiedType(); if (isVM || NewVD->hasAttr<CleanupAttr>() || NewVD->hasAttr<BlocksAttr>()) @@ -3115,23 +3431,42 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier, /// AddOverriddenMethods - See if a method overrides any in the base classes, /// and if so, check that it's a valid override and remember it. -void Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { +bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { // Look for virtual methods in base classes that this method might override. CXXBasePaths Paths; FindOverriddenMethodData Data; Data.Method = MD; Data.S = this; + bool AddedAny = false; if (DC->lookupInBases(&FindOverriddenMethod, &Data, Paths)) { for (CXXBasePaths::decl_iterator I = Paths.found_decls_begin(), E = Paths.found_decls_end(); I != E; ++I) { if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) { if (!CheckOverridingFunctionReturnType(MD, OldMD) && !CheckOverridingFunctionExceptionSpec(MD, OldMD) && - !CheckOverridingFunctionAttributes(MD, OldMD)) + !CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) { MD->addOverriddenMethod(OldMD->getCanonicalDecl()); + AddedAny = true; + } } } } + + return AddedAny; +} + +static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD) { + LookupResult Prev(S, NewFD->getDeclName(), NewFD->getLocation(), + Sema::LookupOrdinaryName, Sema::ForRedeclaration); + S.LookupQualifiedName(Prev, NewFD->getDeclContext()); + assert(!Prev.isAmbiguous() && + "Cannot have an ambiguity in previous-declaration lookup"); + for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); + Func != FuncEnd; ++Func) { + if (isa<FunctionDecl>(*Func) && + isNearlyMatchingFunction(S.Context, cast<FunctionDecl>(*Func), NewFD)) + S.Diag((*Func)->getLocation(), diag::note_member_def_close_match); + } } NamedDecl* @@ -3171,315 +3506,336 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, SC = SC_Static; break; } - case DeclSpec::SCS_private_extern: SC = SC_PrivateExtern;break; + case DeclSpec::SCS_private_extern: SC = SC_PrivateExtern; break; } if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); - bool isFriend = D.getDeclSpec().isFriendSpecified(); - bool isInline = D.getDeclSpec().isInlineSpecified(); - bool isVirtual = D.getDeclSpec().isVirtualSpecified(); - bool isExplicit = D.getDeclSpec().isExplicitSpecified(); - - DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); - FunctionDecl::StorageClass SCAsWritten - = StorageClassSpecToFunctionDeclStorageClass(SCSpec); - - // Check that the return type is not an abstract class type. - // For record types, this is done by the AbstractClassUsageDiagnoser once - // the class has been completely parsed. - if (!DC->isRecord() && - RequireNonAbstractType(D.getIdentifierLoc(), - R->getAs<FunctionType>()->getResultType(), - diag::err_abstract_type_in_decl, - AbstractReturnType)) - D.setInvalidType(); - // Do not allow returning a objc interface by-value. if (R->getAs<FunctionType>()->getResultType()->isObjCObjectType()) { Diag(D.getIdentifierLoc(), diag::err_object_cannot_be_passed_returned_by_value) << 0 - << R->getAs<FunctionType>()->getResultType(); + << R->getAs<FunctionType>()->getResultType(); D.setInvalidType(); } - - bool isVirtualOkay = false; + FunctionDecl *NewFD; - - if (isFriend) { - // C++ [class.friend]p5 - // A function can be defined in a friend declaration of a - // class . . . . Such a function is implicitly inline. - isInline |= IsFunctionDefinition; - } - - if (Name.getNameKind() == DeclarationName::CXXConstructorName) { - // This is a C++ constructor declaration. - assert(DC->isRecord() && - "Constructors can only be declared in a member context"); - - R = CheckConstructorDeclarator(D, R, SC); - - // Create the new declaration - NewFD = CXXConstructorDecl::Create(Context, - cast<CXXRecordDecl>(DC), - NameInfo, R, TInfo, - isExplicit, isInline, - /*isImplicitlyDeclared=*/false); - } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { - // This is a C++ destructor declaration. - if (DC->isRecord()) { - R = CheckDestructorDeclarator(D, R, SC); - - NewFD = CXXDestructorDecl::Create(Context, - cast<CXXRecordDecl>(DC), - NameInfo, R, - isInline, - /*isImplicitlyDeclared=*/false); - NewFD->setTypeSourceInfo(TInfo); - - isVirtualOkay = true; - } else { - Diag(D.getIdentifierLoc(), diag::err_destructor_not_member); - - // Create a FunctionDecl to satisfy the function definition parsing - // code path. - NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(), - Name, R, TInfo, SC, SCAsWritten, isInline, - /*hasPrototype=*/true); - D.setInvalidType(); - } - } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { - if (!DC->isRecord()) { - Diag(D.getIdentifierLoc(), - diag::err_conv_function_not_member); - return 0; - } - - CheckConversionDeclarator(D, R, SC); - NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC), - NameInfo, R, TInfo, - isInline, isExplicit); - - isVirtualOkay = true; - } else if (DC->isRecord()) { - // If the of the function is the same as the name of the record, then this - // must be an invalid constructor that has a return type. - // (The parser checks for a return type and makes the declarator a - // constructor if it has no return type). - // must have an invalid constructor that has a return type - if (Name.getAsIdentifierInfo() && - Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){ - Diag(D.getIdentifierLoc(), diag::err_constructor_return_type) - << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) - << SourceRange(D.getIdentifierLoc()); - return 0; - } - - bool isStatic = SC == SC_Static; - - // [class.free]p1: - // Any allocation function for a class T is a static member - // (even if not explicitly declared static). - if (Name.getCXXOverloadedOperator() == OO_New || - Name.getCXXOverloadedOperator() == OO_Array_New) - isStatic = true; - - // [class.free]p6 Any deallocation function for a class X is a static member - // (even if not explicitly declared static). - if (Name.getCXXOverloadedOperator() == OO_Delete || - Name.getCXXOverloadedOperator() == OO_Array_Delete) - isStatic = true; - - // This is a C++ method declaration. - NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC), - NameInfo, R, TInfo, - isStatic, SCAsWritten, isInline); - - isVirtualOkay = !isStatic; - } else { + bool isInline = D.getDeclSpec().isInlineSpecified(); + bool isFriend = false; + DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); + FunctionDecl::StorageClass SCAsWritten + = StorageClassSpecToFunctionDeclStorageClass(SCSpec); + FunctionTemplateDecl *FunctionTemplate = 0; + bool isExplicitSpecialization = false; + bool isFunctionTemplateSpecialization = false; + unsigned NumMatchedTemplateParamLists = 0; + + if (!getLangOptions().CPlusPlus) { // Determine whether the function was written with a // prototype. This true when: - // - we're in C++ (where every function has a prototype), // - there is a prototype in the declarator, or // - the type R of the function is some kind of typedef or other reference // to a type name (which eventually refers to a function type). bool HasPrototype = - getLangOptions().CPlusPlus || - (D.getNumTypeObjects() && D.getTypeObject(0).Fun.hasPrototype) || - (!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType()); - + (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) || + (!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType()); + NewFD = FunctionDecl::Create(Context, DC, NameInfo, R, TInfo, SC, SCAsWritten, isInline, HasPrototype); - } - - if (D.isInvalidType()) - NewFD->setInvalidDecl(); + if (D.isInvalidType()) + NewFD->setInvalidDecl(); + + // Set the lexical context. + NewFD->setLexicalDeclContext(CurContext); + // Filter out previous declarations that don't match the scope. + FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage()); + } else { + isFriend = D.getDeclSpec().isFriendSpecified(); + bool isVirtual = D.getDeclSpec().isVirtualSpecified(); + bool isExplicit = D.getDeclSpec().isExplicitSpecified(); + bool isVirtualOkay = false; + + // Check that the return type is not an abstract class type. + // For record types, this is done by the AbstractClassUsageDiagnoser once + // the class has been completely parsed. + if (!DC->isRecord() && + RequireNonAbstractType(D.getIdentifierLoc(), + R->getAs<FunctionType>()->getResultType(), + diag::err_abstract_type_in_decl, + AbstractReturnType)) + D.setInvalidType(); - SetNestedNameSpecifier(NewFD, D); - // Set the lexical context. If the declarator has a C++ - // scope specifier, or is the object of a friend declaration, the - // lexical context will be different from the semantic context. - NewFD->setLexicalDeclContext(CurContext); + if (isFriend) { + // C++ [class.friend]p5 + // A function can be defined in a friend declaration of a + // class . . . . Such a function is implicitly inline. + isInline |= IsFunctionDefinition; + } + + if (Name.getNameKind() == DeclarationName::CXXConstructorName) { + // This is a C++ constructor declaration. + assert(DC->isRecord() && + "Constructors can only be declared in a member context"); + + R = CheckConstructorDeclarator(D, R, SC); + + // Create the new declaration + NewFD = CXXConstructorDecl::Create(Context, + cast<CXXRecordDecl>(DC), + NameInfo, R, TInfo, + isExplicit, isInline, + /*isImplicitlyDeclared=*/false); + } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { + // This is a C++ destructor declaration. + if (DC->isRecord()) { + R = CheckDestructorDeclarator(D, R, SC); + + NewFD = CXXDestructorDecl::Create(Context, + cast<CXXRecordDecl>(DC), + NameInfo, R, TInfo, + isInline, + /*isImplicitlyDeclared=*/false); + isVirtualOkay = true; + } else { + Diag(D.getIdentifierLoc(), diag::err_destructor_not_member); - // Match up the template parameter lists with the scope specifier, then - // determine whether we have a template or a template specialization. - FunctionTemplateDecl *FunctionTemplate = 0; - bool isExplicitSpecialization = false; - bool isFunctionTemplateSpecialization = false; - unsigned NumMatchedTemplateParamLists = TemplateParamLists.size(); - bool Invalid = false; - if (TemplateParameterList *TemplateParams - = MatchTemplateParametersToScopeSpecifier( - D.getDeclSpec().getSourceRange().getBegin(), - D.getCXXScopeSpec(), - (TemplateParameterList**)TemplateParamLists.get(), - TemplateParamLists.size(), - isFriend, - isExplicitSpecialization, - Invalid)) { - // All but one template parameter lists have been matching. - --NumMatchedTemplateParamLists; + // Create a FunctionDecl to satisfy the function definition parsing + // code path. + NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(), + Name, R, TInfo, SC, SCAsWritten, isInline, + /*hasPrototype=*/true); + D.setInvalidType(); + } + } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { + if (!DC->isRecord()) { + Diag(D.getIdentifierLoc(), + diag::err_conv_function_not_member); + return 0; + } - if (TemplateParams->size() > 0) { - // This is a function template + CheckConversionDeclarator(D, R, SC); + NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC), + NameInfo, R, TInfo, + isInline, isExplicit); - // Check that we can declare a template here. - if (CheckTemplateDeclScope(S, TemplateParams)) + isVirtualOkay = true; + } else if (DC->isRecord()) { + // If the of the function is the same as the name of the record, then this + // must be an invalid constructor that has a return type. + // (The parser checks for a return type and makes the declarator a + // constructor if it has no return type). + // must have an invalid constructor that has a return type + if (Name.getAsIdentifierInfo() && + Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){ + Diag(D.getIdentifierLoc(), diag::err_constructor_return_type) + << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) + << SourceRange(D.getIdentifierLoc()); return 0; + } + + bool isStatic = SC == SC_Static; + + // [class.free]p1: + // Any allocation function for a class T is a static member + // (even if not explicitly declared static). + if (Name.getCXXOverloadedOperator() == OO_New || + Name.getCXXOverloadedOperator() == OO_Array_New) + isStatic = true; + + // [class.free]p6 Any deallocation function for a class X is a static member + // (even if not explicitly declared static). + if (Name.getCXXOverloadedOperator() == OO_Delete || + Name.getCXXOverloadedOperator() == OO_Array_Delete) + isStatic = true; + + // This is a C++ method declaration. + NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC), + NameInfo, R, TInfo, + isStatic, SCAsWritten, isInline); - FunctionTemplate = FunctionTemplateDecl::Create(Context, DC, + isVirtualOkay = !isStatic; + } else { + // Determine whether the function was written with a + // prototype. This true when: + // - we're in C++ (where every function has a prototype), + NewFD = FunctionDecl::Create(Context, DC, + NameInfo, R, TInfo, SC, SCAsWritten, isInline, + true/*HasPrototype*/); + } + SetNestedNameSpecifier(NewFD, D); + isExplicitSpecialization = false; + isFunctionTemplateSpecialization = false; + NumMatchedTemplateParamLists = TemplateParamLists.size(); + if (D.isInvalidType()) + NewFD->setInvalidDecl(); + + // Set the lexical context. If the declarator has a C++ + // scope specifier, or is the object of a friend declaration, the + // lexical context will be different from the semantic context. + NewFD->setLexicalDeclContext(CurContext); + + // Match up the template parameter lists with the scope specifier, then + // determine whether we have a template or a template specialization. + bool Invalid = false; + if (TemplateParameterList *TemplateParams + = MatchTemplateParametersToScopeSpecifier( + D.getDeclSpec().getSourceRange().getBegin(), + D.getCXXScopeSpec(), + TemplateParamLists.get(), + TemplateParamLists.size(), + isFriend, + isExplicitSpecialization, + Invalid)) { + // All but one template parameter lists have been matching. + --NumMatchedTemplateParamLists; + + if (TemplateParams->size() > 0) { + // This is a function template + + // Check that we can declare a template here. + if (CheckTemplateDeclScope(S, TemplateParams)) + return 0; + + FunctionTemplate = FunctionTemplateDecl::Create(Context, DC, NewFD->getLocation(), Name, TemplateParams, NewFD); - FunctionTemplate->setLexicalDeclContext(CurContext); - NewFD->setDescribedFunctionTemplate(FunctionTemplate); - } else { - // This is a function template specialization. - isFunctionTemplateSpecialization = true; - - // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);". - if (isFriend && isFunctionTemplateSpecialization) { - // We want to remove the "template<>", found here. - SourceRange RemoveRange = TemplateParams->getSourceRange(); - - // If we remove the template<> and the name is not a - // template-id, we're actually silently creating a problem: - // the friend declaration will refer to an untemplated decl, - // and clearly the user wants a template specialization. So - // we need to insert '<>' after the name. - SourceLocation InsertLoc; - if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) { - InsertLoc = D.getName().getSourceRange().getEnd(); - InsertLoc = PP.getLocForEndOfToken(InsertLoc); + FunctionTemplate->setLexicalDeclContext(CurContext); + NewFD->setDescribedFunctionTemplate(FunctionTemplate); + } else { + // This is a function template specialization. + isFunctionTemplateSpecialization = true; + + // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);". + if (isFriend && isFunctionTemplateSpecialization) { + // We want to remove the "template<>", found here. + SourceRange RemoveRange = TemplateParams->getSourceRange(); + + // If we remove the template<> and the name is not a + // template-id, we're actually silently creating a problem: + // the friend declaration will refer to an untemplated decl, + // and clearly the user wants a template specialization. So + // we need to insert '<>' after the name. + SourceLocation InsertLoc; + if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) { + InsertLoc = D.getName().getSourceRange().getEnd(); + InsertLoc = PP.getLocForEndOfToken(InsertLoc); + } + + Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend) + << Name << RemoveRange + << FixItHint::CreateRemoval(RemoveRange) + << FixItHint::CreateInsertion(InsertLoc, "<>"); + } + } } - Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend) - << Name << RemoveRange - << FixItHint::CreateRemoval(RemoveRange) - << FixItHint::CreateInsertion(InsertLoc, "<>"); - } + if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) { + NewFD->setTemplateParameterListsInfo(Context, + NumMatchedTemplateParamLists, + TemplateParamLists.release()); } - } - if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) { - NewFD->setTemplateParameterListsInfo(Context, - NumMatchedTemplateParamLists, - (TemplateParameterList**)TemplateParamLists.release()); - } - - if (Invalid) { - NewFD->setInvalidDecl(); - if (FunctionTemplate) - FunctionTemplate->setInvalidDecl(); - } + if (Invalid) { + NewFD->setInvalidDecl(); + if (FunctionTemplate) + FunctionTemplate->setInvalidDecl(); + } - // C++ [dcl.fct.spec]p5: - // The virtual specifier shall only be used in declarations of - // nonstatic class member functions that appear within a - // member-specification of a class declaration; see 10.3. - // - if (isVirtual && !NewFD->isInvalidDecl()) { - if (!isVirtualOkay) { - Diag(D.getDeclSpec().getVirtualSpecLoc(), - diag::err_virtual_non_function); - } else if (!CurContext->isRecord()) { - // 'virtual' was specified outside of the class. - Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_out_of_class) - << FixItHint::CreateRemoval(D.getDeclSpec().getVirtualSpecLoc()); - } else { - // Okay: Add virtual to the method. - CXXRecordDecl *CurClass = cast<CXXRecordDecl>(DC); - CurClass->setMethodAsVirtual(NewFD); + // C++ [dcl.fct.spec]p5: + // The virtual specifier shall only be used in declarations of + // nonstatic class member functions that appear within a + // member-specification of a class declaration; see 10.3. + // + if (isVirtual && !NewFD->isInvalidDecl()) { + if (!isVirtualOkay) { + Diag(D.getDeclSpec().getVirtualSpecLoc(), + diag::err_virtual_non_function); + } else if (!CurContext->isRecord()) { + // 'virtual' was specified outside of the class. + Diag(D.getDeclSpec().getVirtualSpecLoc(), + diag::err_virtual_out_of_class) + << FixItHint::CreateRemoval(D.getDeclSpec().getVirtualSpecLoc()); + } else if (NewFD->getDescribedFunctionTemplate()) { + // C++ [temp.mem]p3: + // A member function template shall not be virtual. + Diag(D.getDeclSpec().getVirtualSpecLoc(), + diag::err_virtual_member_function_template) + << FixItHint::CreateRemoval(D.getDeclSpec().getVirtualSpecLoc()); + } else { + // Okay: Add virtual to the method. + NewFD->setVirtualAsWritten(true); + } } - } - // C++ [dcl.fct.spec]p3: - // The inline specifier shall not appear on a block scope function declaration. - if (isInline && !NewFD->isInvalidDecl() && getLangOptions().CPlusPlus) { - if (CurContext->isFunctionOrMethod()) { - // 'inline' is not allowed on block scope function declaration. - Diag(D.getDeclSpec().getInlineSpecLoc(), - diag::err_inline_declaration_block_scope) << Name - << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); + // C++ [dcl.fct.spec]p3: + // The inline specifier shall not appear on a block scope function declaration. + if (isInline && !NewFD->isInvalidDecl()) { + if (CurContext->isFunctionOrMethod()) { + // 'inline' is not allowed on block scope function declaration. + Diag(D.getDeclSpec().getInlineSpecLoc(), + diag::err_inline_declaration_block_scope) << Name + << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); + } } - } - // C++ [dcl.fct.spec]p6: - // The explicit specifier shall be used only in the declaration of a - // constructor or conversion function within its class definition; see 12.3.1 - // and 12.3.2. - if (isExplicit && !NewFD->isInvalidDecl()) { - if (!CurContext->isRecord()) { - // 'explicit' was specified outside of the class. - Diag(D.getDeclSpec().getExplicitSpecLoc(), - diag::err_explicit_out_of_class) - << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); - } else if (!isa<CXXConstructorDecl>(NewFD) && - !isa<CXXConversionDecl>(NewFD)) { - // 'explicit' was specified on a function that wasn't a constructor - // or conversion function. - Diag(D.getDeclSpec().getExplicitSpecLoc(), - diag::err_explicit_non_ctor_or_conv_function) - << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); - } - } - - // Filter out previous declarations that don't match the scope. - FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage()); - - if (isFriend) { - // DC is the namespace in which the function is being declared. - assert((DC->isFileContext() || !Previous.empty()) && - "previously-undeclared friend function being created " - "in a non-namespace context"); - - // For now, claim that the objects have no previous declaration. - if (FunctionTemplate) { - FunctionTemplate->setObjectOfFriendDecl(false); - FunctionTemplate->setAccess(AS_public); + // C++ [dcl.fct.spec]p6: + // The explicit specifier shall be used only in the declaration of a + // constructor or conversion function within its class definition; see 12.3.1 + // and 12.3.2. + if (isExplicit && !NewFD->isInvalidDecl()) { + if (!CurContext->isRecord()) { + // 'explicit' was specified outside of the class. + Diag(D.getDeclSpec().getExplicitSpecLoc(), + diag::err_explicit_out_of_class) + << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); + } else if (!isa<CXXConstructorDecl>(NewFD) && + !isa<CXXConversionDecl>(NewFD)) { + // 'explicit' was specified on a function that wasn't a constructor + // or conversion function. + Diag(D.getDeclSpec().getExplicitSpecLoc(), + diag::err_explicit_non_ctor_or_conv_function) + << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); + } + } + + // Filter out previous declarations that don't match the scope. + FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage()); + + if (isFriend) { + // For now, claim that the objects have no previous declaration. + if (FunctionTemplate) { + FunctionTemplate->setObjectOfFriendDecl(false); + FunctionTemplate->setAccess(AS_public); + } + NewFD->setObjectOfFriendDecl(false); + NewFD->setAccess(AS_public); } - NewFD->setObjectOfFriendDecl(false); - NewFD->setAccess(AS_public); - } - if (SC == SC_Static && isa<CXXMethodDecl>(NewFD) && - !CurContext->isRecord()) { - // C++ [class.static]p1: - // A data or function member of a class may be declared static - // in a class definition, in which case it is a static member of - // the class. + if (isa<CXXMethodDecl>(NewFD) && DC == CurContext && IsFunctionDefinition) { + // A method is implicitly inline if it's defined in its class + // definition. + NewFD->setImplicitlyInline(); + } - // Complain about the 'static' specifier if it's on an out-of-line - // member function definition. - Diag(D.getDeclSpec().getStorageClassSpecLoc(), - diag::err_static_out_of_line) - << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); - } + if (SC == SC_Static && isa<CXXMethodDecl>(NewFD) && + !CurContext->isRecord()) { + // C++ [class.static]p1: + // A data or function member of a class may be declared static + // in a class definition, in which case it is a static member of + // the class. + // Complain about the 'static' specifier if it's on an out-of-line + // member function definition. + Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::err_static_out_of_line) + << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); + } + } + // Handle GNU asm-label extension (encoded as an attribute). if (Expr *E = (Expr*) D.getAsmLabel()) { // The parser guarantees this is a string. @@ -3491,8 +3847,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Copy the parameter declarations from the declarator D to the function // declaration NewFD, if they are available. First scavenge them into Params. llvm::SmallVector<ParmVarDecl*, 16> Params; - if (D.getNumTypeObjects() > 0) { - DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + if (D.isFunctionDeclarator()) { + DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs // function that takes no arguments, not a function that takes a @@ -3510,7 +3866,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (getLangOptions().CPlusPlus && Param->getType().getUnqualifiedType() != Context.VoidTy) Diag(Param->getLocation(), diag::err_param_typedef_of_void); - // FIXME: Leaks decl? } 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); @@ -3547,168 +3902,209 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Finally, we know we have the right number of parameters, install them. NewFD->setParams(Params.data(), Params.size()); - // If the declarator is a template-id, translate the parser's template - // argument list into our AST format. - bool HasExplicitTemplateArgs = false; - TemplateArgumentListInfo TemplateArgs; - if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { - TemplateIdAnnotation *TemplateId = D.getName().TemplateId; - TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); - TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); - ASTTemplateArgsPtr TemplateArgsPtr(*this, - TemplateId->getTemplateArgs(), - TemplateId->NumArgs); - translateTemplateArguments(TemplateArgsPtr, - TemplateArgs); - TemplateArgsPtr.release(); + // Process the non-inheritable attributes on this declaration. + ProcessDeclAttributes(S, NewFD, D, + /*NonInheritable=*/true, /*Inheritable=*/false); + + if (!getLangOptions().CPlusPlus) { + // Perform semantic checking on the function declaration. + bool isExplctSpecialization=false; + CheckFunctionDeclaration(S, NewFD, Previous, isExplctSpecialization, + Redeclaration); + assert((NewFD->isInvalidDecl() || !Redeclaration || + Previous.getResultKind() != LookupResult::FoundOverloaded) && + "previous declaration set still overloaded"); + } else { + // If the declarator is a template-id, translate the parser's template + // argument list into our AST format. + bool HasExplicitTemplateArgs = false; + TemplateArgumentListInfo TemplateArgs; + if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { + TemplateIdAnnotation *TemplateId = D.getName().TemplateId; + TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); + TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); + ASTTemplateArgsPtr TemplateArgsPtr(*this, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + translateTemplateArguments(TemplateArgsPtr, + TemplateArgs); + TemplateArgsPtr.release(); - HasExplicitTemplateArgs = true; + HasExplicitTemplateArgs = true; - if (FunctionTemplate) { - // FIXME: Diagnose function template with explicit template - // arguments. - HasExplicitTemplateArgs = false; - } else if (!isFunctionTemplateSpecialization && - !D.getDeclSpec().isFriendSpecified()) { - // We have encountered something that the user meant to be a - // specialization (because it has explicitly-specified template - // arguments) but that was not introduced with a "template<>" (or had - // too few of them). - Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header) - << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc) - << FixItHint::CreateInsertion( - D.getDeclSpec().getSourceRange().getBegin(), - "template<> "); - isFunctionTemplateSpecialization = true; - } else { - // "friend void foo<>(int);" is an implicit specialization decl. - isFunctionTemplateSpecialization = true; - } - } else if (isFriend && isFunctionTemplateSpecialization) { - // This combination is only possible in a recovery case; the user - // wrote something like: - // template <> friend void foo(int); - // which we're recovering from as if the user had written: - // friend void foo<>(int); - // Go ahead and fake up a template id. - HasExplicitTemplateArgs = true; - TemplateArgs.setLAngleLoc(D.getIdentifierLoc()); - TemplateArgs.setRAngleLoc(D.getIdentifierLoc()); - } - - // If it's a friend (and only if it's a friend), it's possible - // that either the specialized function type or the specialized - // template is dependent, and therefore matching will fail. In - // this case, don't check the specialization yet. - if (isFunctionTemplateSpecialization && isFriend && - (NewFD->getType()->isDependentType() || DC->isDependentContext())) { - assert(HasExplicitTemplateArgs && - "friend function specialization without template args"); - if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs, - Previous)) - NewFD->setInvalidDecl(); - } else if (isFunctionTemplateSpecialization) { - if (CheckFunctionTemplateSpecialization(NewFD, - (HasExplicitTemplateArgs ? &TemplateArgs : 0), - Previous)) - NewFD->setInvalidDecl(); - } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) { - if (CheckMemberSpecialization(NewFD, Previous)) - NewFD->setInvalidDecl(); - } + if (FunctionTemplate) { + // Function template with explicit template arguments. + Diag(D.getIdentifierLoc(), diag::err_function_template_partial_spec) + << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc); + + HasExplicitTemplateArgs = false; + } else if (!isFunctionTemplateSpecialization && + !D.getDeclSpec().isFriendSpecified()) { + // We have encountered something that the user meant to be a + // specialization (because it has explicitly-specified template + // arguments) but that was not introduced with a "template<>" (or had + // too few of them). + Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header) + << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc) + << FixItHint::CreateInsertion( + D.getDeclSpec().getSourceRange().getBegin(), + "template<> "); + isFunctionTemplateSpecialization = true; + } else { + // "friend void foo<>(int);" is an implicit specialization decl. + isFunctionTemplateSpecialization = true; + } + } else if (isFriend && isFunctionTemplateSpecialization) { + // This combination is only possible in a recovery case; the user + // wrote something like: + // template <> friend void foo(int); + // which we're recovering from as if the user had written: + // friend void foo<>(int); + // Go ahead and fake up a template id. + HasExplicitTemplateArgs = true; + TemplateArgs.setLAngleLoc(D.getIdentifierLoc()); + TemplateArgs.setRAngleLoc(D.getIdentifierLoc()); + } + + // If it's a friend (and only if it's a friend), it's possible + // that either the specialized function type or the specialized + // template is dependent, and therefore matching will fail. In + // this case, don't check the specialization yet. + if (isFunctionTemplateSpecialization && isFriend && + (NewFD->getType()->isDependentType() || DC->isDependentContext())) { + assert(HasExplicitTemplateArgs && + "friend function specialization without template args"); + if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs, + Previous)) + NewFD->setInvalidDecl(); + } else if (isFunctionTemplateSpecialization) { + if (CheckFunctionTemplateSpecialization(NewFD, + (HasExplicitTemplateArgs ? &TemplateArgs : 0), + Previous)) + NewFD->setInvalidDecl(); + } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) { + if (CheckMemberSpecialization(NewFD, Previous)) + NewFD->setInvalidDecl(); + } - // Perform semantic checking on the function declaration. - bool OverloadableAttrRequired = false; // FIXME: HACK! - CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization, - Redeclaration, /*FIXME:*/OverloadableAttrRequired); + // Perform semantic checking on the function declaration. + CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization, + Redeclaration); - assert((NewFD->isInvalidDecl() || !Redeclaration || - Previous.getResultKind() != LookupResult::FoundOverloaded) && - "previous declaration set still overloaded"); + assert((NewFD->isInvalidDecl() || !Redeclaration || + Previous.getResultKind() != LookupResult::FoundOverloaded) && + "previous declaration set still overloaded"); - NamedDecl *PrincipalDecl = (FunctionTemplate - ? cast<NamedDecl>(FunctionTemplate) - : NewFD); + NamedDecl *PrincipalDecl = (FunctionTemplate + ? cast<NamedDecl>(FunctionTemplate) + : NewFD); - if (isFriend && Redeclaration) { - AccessSpecifier Access = AS_public; - if (!NewFD->isInvalidDecl()) - Access = NewFD->getPreviousDeclaration()->getAccess(); + if (isFriend && Redeclaration) { + AccessSpecifier Access = AS_public; + if (!NewFD->isInvalidDecl()) + Access = NewFD->getPreviousDeclaration()->getAccess(); - NewFD->setAccess(Access); - if (FunctionTemplate) FunctionTemplate->setAccess(Access); + NewFD->setAccess(Access); + if (FunctionTemplate) FunctionTemplate->setAccess(Access); - PrincipalDecl->setObjectOfFriendDecl(true); - } + PrincipalDecl->setObjectOfFriendDecl(true); + } - if (NewFD->isOverloadedOperator() && !DC->isRecord() && - PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) - PrincipalDecl->setNonMemberOperator(); + if (NewFD->isOverloadedOperator() && !DC->isRecord() && + PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + PrincipalDecl->setNonMemberOperator(); - // If we have a function template, check the template parameter - // list. This will check and merge default template arguments. - if (FunctionTemplate) { - FunctionTemplateDecl *PrevTemplate = FunctionTemplate->getPreviousDeclaration(); - CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(), - PrevTemplate? PrevTemplate->getTemplateParameters() : 0, - D.getDeclSpec().isFriendSpecified()? TPC_FriendFunctionTemplate - : TPC_FunctionTemplate); - } + // If we have a function template, check the template parameter + // list. This will check and merge default template arguments. + if (FunctionTemplate) { + FunctionTemplateDecl *PrevTemplate = FunctionTemplate->getPreviousDeclaration(); + CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(), + PrevTemplate? PrevTemplate->getTemplateParameters() : 0, + D.getDeclSpec().isFriendSpecified() + ? (IsFunctionDefinition + ? TPC_FriendFunctionTemplateDefinition + : TPC_FriendFunctionTemplate) + : (D.getCXXScopeSpec().isSet() && + DC && DC->isRecord() && + DC->isDependentContext()) + ? TPC_ClassTemplateMember + : TPC_FunctionTemplate); + } + + if (NewFD->isInvalidDecl()) { + // Ignore all the rest of this. + } else if (!Redeclaration) { + // Fake up an access specifier if it's supposed to be a class member. + if (isa<CXXRecordDecl>(NewFD->getDeclContext())) + NewFD->setAccess(AS_public); + + // Qualified decls generally require a previous declaration. + if (D.getCXXScopeSpec().isSet()) { + // ...with the major exception of templated-scope or + // dependent-scope friend declarations. + + // TODO: we currently also suppress this check in dependent + // contexts because (1) the parameter depth will be off when + // matching friend templates and (2) we might actually be + // selecting a friend based on a dependent factor. But there + // are situations where these conditions don't apply and we + // can actually do this check immediately. + if (isFriend && + (NumMatchedTemplateParamLists || + D.getCXXScopeSpec().getScopeRep()->isDependent() || + CurContext->isDependentContext())) { + // ignore these + } else { + // The user tried to provide an out-of-line definition for a + // function that is a member of a class or namespace, but there + // was no such member function declared (C++ [class.mfct]p2, + // C++ [namespace.memdef]p2). For example: + // + // class X { + // void f() const; + // }; + // + // void X::f() { } // ill-formed + // + // Complain about this problem, and attempt to suggest close + // matches (e.g., those that differ only in cv-qualifiers and + // whether the parameter types are references). + Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match) + << Name << DC << D.getCXXScopeSpec().getRange(); + NewFD->setInvalidDecl(); + + DiagnoseInvalidRedeclaration(*this, NewFD); + } - if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) { - // Fake up an access specifier if it's supposed to be a class member. - if (!Redeclaration && isa<CXXRecordDecl>(NewFD->getDeclContext())) - NewFD->setAccess(AS_public); + // Unqualified local friend declarations are required to resolve + // to something. + } else if (isFriend && cast<CXXRecordDecl>(CurContext)->isLocalClass()) { + Diag(D.getIdentifierLoc(), diag::err_no_matching_local_friend); + NewFD->setInvalidDecl(); + DiagnoseInvalidRedeclaration(*this, NewFD); + } - // An out-of-line member function declaration must also be a - // definition (C++ [dcl.meaning]p1). - // Note that this is not the case for explicit specializations of - // function templates or member functions of class templates, per - // C++ [temp.expl.spec]p2. We also allow these declarations as an extension - // for compatibility with old SWIG code which likes to generate them. - if (!IsFunctionDefinition && !isFriend && - !isFunctionTemplateSpecialization && !isExplicitSpecialization) { + } else if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() && + !isFriend && !isFunctionTemplateSpecialization && + !isExplicitSpecialization) { + // An out-of-line member function declaration must also be a + // definition (C++ [dcl.meaning]p1). + // Note that this is not the case for explicit specializations of + // function templates or member functions of class templates, per + // C++ [temp.expl.spec]p2. We also allow these declarations as an extension + // for compatibility with old SWIG code which likes to generate them. Diag(NewFD->getLocation(), diag::ext_out_of_line_declaration) << D.getCXXScopeSpec().getRange(); } - if (!Redeclaration && !(isFriend && CurContext->isDependentContext())) { - // The user tried to provide an out-of-line definition for a - // function that is a member of a class or namespace, but there - // was no such member function declared (C++ [class.mfct]p2, - // C++ [namespace.memdef]p2). For example: - // - // class X { - // void f() const; - // }; - // - // void X::f() { } // ill-formed - // - // Complain about this problem, and attempt to suggest close - // matches (e.g., those that differ only in cv-qualifiers and - // whether the parameter types are references). - Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match) - << Name << DC << D.getCXXScopeSpec().getRange(); - NewFD->setInvalidDecl(); - - LookupResult Prev(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName, - ForRedeclaration); - LookupQualifiedName(Prev, DC); - assert(!Prev.isAmbiguous() && - "Cannot have an ambiguity in previous-declaration lookup"); - for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); - Func != FuncEnd; ++Func) { - if (isa<FunctionDecl>(*Func) && - isNearlyMatchingFunction(Context, cast<FunctionDecl>(*Func), NewFD)) - Diag((*Func)->getLocation(), diag::note_member_def_close_match); - } - } } - + + // Handle attributes. We need to have merged decls when handling attributes // (for example to check for conflicts, etc). // FIXME: This needs to happen before we merge declarations. Then, // let attribute merging cope with attribute conflicts. - ProcessDeclAttributes(S, NewFD, D); + ProcessDeclAttributes(S, NewFD, D, + /*NonInheritable=*/false, /*Inheritable=*/true); // attributes declared post-definition are currently ignored // FIXME: This should happen during attribute merging @@ -3723,17 +4119,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, AddKnownFunctionAttributes(NewFD); - if (OverloadableAttrRequired && !NewFD->hasAttr<OverloadableAttr>()) { - // If a function name is overloadable in C, then every function - // with that name must be marked "overloadable". - Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) - << Redeclaration << NewFD; - if (!Previous.empty()) - Diag(Previous.getRepresentativeDecl()->getLocation(), - diag::note_attribute_overloadable_prev_overload); - NewFD->addAttr(::new (Context) OverloadableAttr(SourceLocation(), Context)); - } - if (NewFD->hasAttr<OverloadableAttr>() && !NewFD->getType()->getAs<FunctionProtoType>()) { Diag(NewFD->getLocation(), @@ -3742,9 +4127,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Turn this into a variadic function with no parameters. const FunctionType *FT = NewFD->getType()->getAs<FunctionType>(); - QualType R = Context.getFunctionType(FT->getResultType(), - 0, 0, true, 0, false, false, 0, 0, - FT->getExtInfo()); + FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = true; + EPI.ExtInfo = FT->getExtInfo(); + + QualType R = Context.getFunctionType(FT->getResultType(), 0, 0, EPI); NewFD->setType(R); } @@ -3762,14 +4149,28 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Set this FunctionDecl's range up to the right paren. NewFD->setLocEnd(D.getSourceRange().getEnd()); - if (FunctionTemplate && NewFD->isInvalidDecl()) - FunctionTemplate->setInvalidDecl(); - - if (FunctionTemplate) - return FunctionTemplate; + if (getLangOptions().CPlusPlus) { + if (FunctionTemplate) { + if (NewFD->isInvalidDecl()) + FunctionTemplate->setInvalidDecl(); + return FunctionTemplate; + } + } MarkUnusedFileScopedDecl(NewFD); + if (getLangOptions().CUDA) + if (IdentifierInfo *II = NewFD->getIdentifier()) + if (!NewFD->isInvalidDecl() && + NewFD->getDeclContext()->getRedeclContext()->isTranslationUnit()) { + if (II->isStr("cudaConfigureCall")) { + if (!R->getAs<FunctionType>()->getResultType()->isScalarType()) + Diag(NewFD->getLocation(), diag::err_config_scalar_return); + + Context.setcudaConfigureCallDecl(NewFD); + } + } + return NewFD; } @@ -3790,8 +4191,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, bool IsExplicitSpecialization, - bool &Redeclaration, - bool &OverloadableAttrRequired) { + bool &Redeclaration) { // If NewFD is already known erroneous, don't do any of this checking. if (NewFD->isInvalidDecl()) { // If this is a class member, mark the class invalid immediately. @@ -3836,9 +4236,6 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, Redeclaration = true; OldDecl = Previous.getFoundDecl(); } else { - if (!getLangOptions().CPlusPlus) - OverloadableAttrRequired = true; - switch (CheckOverload(S, NewFD, Previous, OldDecl, /*NewIsUsingDecl*/ false)) { case Ovl_Match: @@ -3853,6 +4250,23 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, Redeclaration = false; break; } + + if (!getLangOptions().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) { + // If a function name is overloadable in C, then every function + // with that name must be marked "overloadable". + Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) + << Redeclaration << NewFD; + NamedDecl *OverloadedDecl = 0; + if (Redeclaration) + OverloadedDecl = OldDecl; + else if (!Previous.empty()) + OverloadedDecl = Previous.getRepresentativeDecl(); + if (OverloadedDecl) + Diag(OverloadedDecl->getLocation(), + diag::note_attribute_overloadable_prev_overload); + NewFD->addAttr(::new (Context) OverloadableAttr(SourceLocation(), + Context)); + } } if (Redeclaration) { @@ -3907,23 +4321,11 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, DeclarationName Name = Context.DeclarationNames.getCXXDestructorName( Context.getCanonicalType(ClassType)); -// NewFD->getDeclName().dump(); -// Name.dump(); if (NewFD->getDeclName() != Name) { Diag(NewFD->getLocation(), diag::err_destructor_name); return NewFD->setInvalidDecl(); } } - - Record->setUserDeclaredDestructor(true); - // C++ [class]p4: A POD-struct is an aggregate class that has [...] no - // user-defined destructor. - Record->setPOD(false); - - // C++ [class.dtor]p3: A destructor is trivial if it is an implicitly- - // declared destructor. - // FIXME: C++0x: don't do this for "= default" destructors - Record->setHasTrivialDestructor(false); } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD)) { ActOnConversionDeclarator(Conversion); @@ -3932,8 +4334,23 @@ void 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()) - AddOverriddenMethods(Method->getParent(), Method); + !Method->getDescribedFunctionTemplate()) { + 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); + } + } + } + } } // Extra checking for C++ overloaded operators (C++ [over.oper]). @@ -3951,6 +4368,18 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // during delayed parsing anyway. if (!CurContext->isRecord()) CheckCXXDefaultArguments(NewFD); + + // If this function declares a builtin function, check the type of this + // declaration against the expected type for the builtin. + if (unsigned BuiltinID = NewFD->getBuiltinID()) { + ASTContext::GetBuiltinTypeError Error; + QualType T = Context.GetBuiltinType(BuiltinID, Error); + if (!T.isNull() && !Context.hasSameType(T, NewFD->getType())) { + // The type of this function differs from the type of the builtin, + // so forget about the builtin entirely. + Context.BuiltinInfo.ForgetBuiltin(BuiltinID, Context.Idents); + } + } } } @@ -3976,7 +4405,6 @@ void Sema::CheckMain(FunctionDecl* FD) { const FunctionType* FT = T->getAs<FunctionType>(); if (!Context.hasSameUnqualifiedType(FT->getResultType(), Context.IntTy)) { - // TODO: add a replacement fixit to turn the return type into 'int'. Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint); FD->setInvalidDecl(true); } @@ -4043,6 +4471,11 @@ void Sema::CheckMain(FunctionDecl* FD) { if (nparams == 1 && !FD->isInvalidDecl()) { Diag(FD->getLocation(), diag::warn_main_one_arg); } + + if (!FD->isInvalidDecl() && FD->getDescribedFunctionTemplate()) { + Diag(FD->getLocation(), diag::err_main_template_decl); + FD->setInvalidDecl(); + } } bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { @@ -4061,17 +4494,14 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { return true; } -void Sema::AddInitializerToDecl(Decl *dcl, Expr *init) { - AddInitializerToDecl(dcl, init, /*DirectInit=*/false); -} - /// AddInitializerToDecl - Adds the initializer Init to the /// declaration dcl. If DirectInit is true, this is C++ direct /// initialization rather than copy initialization. -void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { +void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, + bool DirectInit, bool TypeMayContainAuto) { // If there is no declaration, there was an error parsing it. Just ignore // the initializer. - if (RealDecl == 0) + if (RealDecl == 0 || RealDecl->isInvalidDecl()) return; if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) { @@ -4095,14 +4525,32 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { if (getLangOptions().CPlusPlus && RealDecl->getLexicalDeclContext()->isRecord() && isa<NamedDecl>(RealDecl)) - Diag(RealDecl->getLocation(), diag::err_member_initialization) - << cast<NamedDecl>(RealDecl)->getDeclName(); + Diag(RealDecl->getLocation(), diag::err_member_initialization); else Diag(RealDecl->getLocation(), diag::err_illegal_initializer); RealDecl->setInvalidDecl(); return; } + // C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. + if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) { + VDecl->setParsingAutoInit(false); + + QualType DeducedType; + if (!DeduceAutoType(VDecl->getType(), Init, DeducedType)) { + Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure) + << VDecl->getDeclName() << VDecl->getType() << Init->getType() + << Init->getSourceRange(); + RealDecl->setInvalidDecl(); + return; + } + VDecl->setType(DeducedType); + + // If this is a redeclaration, check that the type we just deduced matches + // the previously declared type. + if (VarDecl *Old = VDecl->getPreviousDeclaration()) + MergeVarDeclTypes(VDecl, Old); + } // A definition must end up with a complete type, which means it must be @@ -4132,27 +4580,34 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { return; } - // C++ [class.static.data]p4 - // If a static data member is of const integral or const - // enumeration type, its declaration in the class definition can - // specify a constant-initializer which shall be an integral - // constant expression (5.19). In that case, the member can appear - // in integral constant expressions. The member shall still be - // defined in a namespace scope if it is used in the program and the - // namespace scope definition shall not contain an initializer. - // - // We already performed a redefinition check above, but for static - // data members we also need to check whether there was an in-class - // declaration with an initializer. const VarDecl* PrevInit = 0; - if (VDecl->isStaticDataMember() && VDecl->getAnyInitializer(PrevInit)) { - Diag(VDecl->getLocation(), diag::err_redefinition) << VDecl->getDeclName(); - Diag(PrevInit->getLocation(), diag::note_previous_definition); - return; - } + if (getLangOptions().CPlusPlus) { + // C++ [class.static.data]p4 + // If a static data member is of const integral or const + // enumeration type, its declaration in the class definition can + // specify a constant-initializer which shall be an integral + // constant expression (5.19). In that case, the member can appear + // in integral constant expressions. The member shall still be + // defined in a namespace scope if it is used in the program and the + // namespace scope definition shall not contain an initializer. + // + // We already performed a redefinition check above, but for static + // data members we also need to check whether there was an in-class + // declaration with an initializer. + if (VDecl->isStaticDataMember() && VDecl->getAnyInitializer(PrevInit)) { + Diag(VDecl->getLocation(), diag::err_redefinition) << VDecl->getDeclName(); + Diag(PrevInit->getLocation(), diag::note_previous_definition); + return; + } - if (getLangOptions().CPlusPlus && VDecl->hasLocalStorage()) - getCurFunction()->setHasBranchProtectedScope(); + if (VDecl->hasLocalStorage()) + getCurFunction()->setHasBranchProtectedScope(); + + if (DiagnoseUnexpandedParameterPack(Init, UPPC_Initializer)) { + VDecl->setInvalidDecl(); + return; + } + } // Capture the variable that is being initialized and the style of // initialization. @@ -4169,7 +4624,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // Get the decls type and save a reference for later, since // CheckInitializerTypes may change it. QualType DclT = VDecl->getType(), SavT = DclT; - if (VDecl->isBlockVarDecl()) { + if (VDecl->isLocalVarDecl()) { if (VDecl->hasExternalStorage()) { // C99 6.7.8p5 Diag(VDecl->getLocation(), diag::err_block_extern_cant_init); VDecl->setInvalidDecl(); @@ -4200,34 +4655,38 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // static const int value = 17; // }; - // Attach the initializer - VDecl->setInit(Init); + // Try to perform the initialization regardless. + if (!VDecl->isInvalidDecl()) { + InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, &Init, 1), + &DclT); + if (Result.isInvalid()) { + VDecl->setInvalidDecl(); + return; + } + + Init = Result.takeAs<Expr>(); + } // C++ [class.mem]p4: // A member-declarator can contain a constant-initializer only // if it declares a static member (9.4) of const integral or // const enumeration type, see 9.4.2. QualType T = VDecl->getType(); - if (!T->isDependentType() && - (!Context.getCanonicalType(T).isConstQualified() || - !T->isIntegralOrEnumerationType())) { - Diag(VDecl->getLocation(), diag::err_member_initialization) - << VDecl->getDeclName() << Init->getSourceRange(); + + // Do nothing on dependent types. + if (T->isDependentType()) { + + // Require constness. + } else if (!T.isConstQualified()) { + Diag(VDecl->getLocation(), diag::err_in_class_initializer_non_const) + << Init->getSourceRange(); VDecl->setInvalidDecl(); - } else { - // C++ [class.static.data]p4: - // If a static data member is of const integral or const - // enumeration type, its declaration in the class definition - // can specify a constant-initializer which shall be an - // integral constant expression (5.19). - if (!Init->isTypeDependent() && - !Init->getType()->isIntegralOrEnumerationType()) { - // We have a non-dependent, non-integral or enumeration type. - Diag(Init->getSourceRange().getBegin(), - diag::err_in_class_initializer_non_integral_type) - << Init->getType() << Init->getSourceRange(); - VDecl->setInvalidDecl(); - } else if (!Init->isTypeDependent() && !Init->isValueDependent()) { + + // We allow integer constant expressions in all cases. + } else if (T->isIntegralOrEnumerationType()) { + if (!Init->isValueDependent()) { // Check whether the expression is a constant expression. llvm::APSInt Value; SourceLocation Loc; @@ -4235,12 +4694,37 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { Diag(Loc, diag::err_in_class_initializer_non_constant) << Init->getSourceRange(); VDecl->setInvalidDecl(); - } else if (!VDecl->getType()->isDependentType()) - ImpCastExprToType(Init, VDecl->getType(), CK_IntegralCast); + } + } + + // We allow floating-point constants as an extension in C++03, and + // C++0x has far more complicated rules that we don't really + // implement fully. + } else { + bool Allowed = false; + if (getLangOptions().CPlusPlus0x) { + Allowed = T->isLiteralType(); + } else if (T->isFloatingType()) { // also permits complex, which is ok + Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type) + << T << Init->getSourceRange(); + Allowed = true; + } + + if (!Allowed) { + Diag(VDecl->getLocation(), diag::err_in_class_initializer_bad_type) + << T << Init->getSourceRange(); + VDecl->setInvalidDecl(); + + // TODO: there are probably expressions that pass here that shouldn't. + } else if (!Init->isValueDependent() && + !Init->isConstantInitializer(Context, false)) { + Diag(Init->getExprLoc(), diag::err_in_class_initializer_non_constant) + << Init->getSourceRange(); + VDecl->setInvalidDecl(); } } } else if (VDecl->isFileVarDecl()) { - if (VDecl->getStorageClass() == SC_Extern && + if (VDecl->getStorageClassAsWritten() == SC_Extern && (!getLangOptions().CPlusPlus || !Context.getBaseElementType(VDecl->getType()).isConstQualified())) Diag(VDecl->getLocation(), diag::warn_extern_init); @@ -4273,28 +4757,35 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { Init->setType(DclT); } - Init = MaybeCreateCXXExprWithTemporaries(Init); + + // If this variable is a local declaration with record type, make sure it + // doesn't have a flexible member initialization. We only support this as a + // global/static definition. + if (VDecl->hasLocalStorage()) + if (const RecordType *RT = VDecl->getType()->getAs<RecordType>()) + if (RT->getDecl()->hasFlexibleArrayMember()) { + // Check whether the initializer tries to initialize the flexible + // array member itself to anything other than an empty initializer list. + if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { + unsigned Index = std::distance(RT->getDecl()->field_begin(), + RT->getDecl()->field_end()) - 1; + if (Index < ILE->getNumInits() && + !(isa<InitListExpr>(ILE->getInit(Index)) && + cast<InitListExpr>(ILE->getInit(Index))->getNumInits() == 0)) { + Diag(VDecl->getLocation(), diag::err_nonstatic_flexible_variable); + VDecl->setInvalidDecl(); + } + } + } + + // Check any implicit conversions within the expression. + CheckImplicitConversions(Init, VDecl->getLocation()); + + Init = MaybeCreateExprWithCleanups(Init); // Attach the initializer to the decl. VDecl->setInit(Init); - if (getLangOptions().CPlusPlus) { - if (!VDecl->isInvalidDecl() && - !VDecl->getDeclContext()->isDependentContext() && - VDecl->hasGlobalStorage() && !VDecl->isStaticLocal() && - !Init->isConstantInitializer(Context, - VDecl->getType()->isReferenceType())) - Diag(VDecl->getLocation(), diag::warn_global_constructor) - << Init->getSourceRange(); - - // Make sure we mark the destructor as used if necessary. - QualType InitType = VDecl->getType(); - while (const ArrayType *Array = Context.getAsArrayType(InitType)) - InitType = Context.getBaseElementType(Array); - if (const RecordType *Record = InitType->getAs<RecordType>()) - FinalizeVarWithDestructor(VDecl, Record); - } - - return; + CheckCompleteVariableDeclaration(VDecl); } /// ActOnInitializerError - Given that there was an error parsing an @@ -4308,6 +4799,13 @@ void Sema::ActOnInitializerError(Decl *D) { VarDecl *VD = dyn_cast<VarDecl>(D); if (!VD) return; + // Auto types are meaningless if we can't make sense of the initializer. + if (VD->isParsingAutoInit()) { + VD->setParsingAutoInit(false); + VD->setInvalidDecl(); + return; + } + QualType Ty = VD->getType(); if (Ty->isDependentType()) return; @@ -4332,7 +4830,7 @@ void Sema::ActOnInitializerError(Decl *D) { } void Sema::ActOnUninitializedDecl(Decl *RealDecl, - bool TypeContainsUndeducedAuto) { + bool TypeMayContainAuto) { // If there is no declaration, there was an error parsing it. Just ignore it. if (RealDecl == 0) return; @@ -4341,7 +4839,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, QualType Type = Var->getType(); // C++0x [dcl.spec.auto]p3 - if (TypeContainsUndeducedAuto) { + if (TypeMayContainAuto && Type->getContainedAutoType()) { + Var->setParsingAutoInit(false); + Diag(Var->getLocation(), diag::err_auto_var_requires_init) << Var->getDeclName() << Type; Var->setInvalidDecl(); @@ -4365,7 +4865,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, // Block scope. C99 6.7p7: If an identifier for an object is // declared with no linkage (C99 6.2.2p6), the type for the // object shall be complete. - if (!Type->isDependentType() && Var->isBlockVarDecl() && + if (!Type->isDependentType() && Var->isLocalVarDecl() && !Var->getLinkage() && !Var->isInvalidDecl() && RequireCompleteType(Var->getLocation(), Type, diag::err_typecheck_decl_incomplete_type)) @@ -4488,22 +4988,62 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, MultiExprArg(*this, 0, 0)); if (Init.isInvalid()) Var->setInvalidDecl(); - else if (Init.get()) { - Var->setInit(MaybeCreateCXXExprWithTemporaries(Init.takeAs<Expr>())); - - if (getLangOptions().CPlusPlus && !Var->isInvalidDecl() && - Var->hasGlobalStorage() && !Var->isStaticLocal() && - !Var->getDeclContext()->isDependentContext() && - !Var->getInit()->isConstantInitializer(Context, false)) - Diag(Var->getLocation(), diag::warn_global_constructor); - } + else if (Init.get()) + Var->setInit(MaybeCreateExprWithCleanups(Init.get())); } - if (!Var->isInvalidDecl() && getLangOptions().CPlusPlus && Record) - FinalizeVarWithDestructor(Var, Record); + CheckCompleteVariableDeclaration(Var); } } +void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { + if (var->isInvalidDecl()) return; + + // All the following checks are C++ only. + if (!getLangOptions().CPlusPlus) return; + + QualType baseType = Context.getBaseElementType(var->getType()); + if (baseType->isDependentType()) return; + + // __block variables might require us to capture a copy-initializer. + if (var->hasAttr<BlocksAttr>()) { + // It's currently invalid to ever have a __block variable with an + // array type; should we diagnose that here? + + // 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, type, VK_LValue, poi); + ExprResult result = + PerformCopyInitialization( + InitializedEntity::InitializeBlock(poi, type, false), + poi, Owned(varRef)); + if (!result.isInvalid()) { + result = MaybeCreateExprWithCleanups(result); + Expr *init = result.takeAs<Expr>(); + Context.setBlockVarCopyInits(var, init); + } + } + } + + // Check for global constructors. + if (!var->getDeclContext()->isDependentContext() && + var->hasGlobalStorage() && + !var->isStaticLocal() && + var->getInit() && + !var->getInit()->isConstantInitializer(Context, + baseType->isReferenceType())) + Diag(var->getLocation(), diag::warn_global_constructor) + << var->getInit()->getSourceRange(); + + // Require the destructor. + if (const RecordType *recordType = baseType->getAs<RecordType>()) + FinalizeVarWithDestructor(var, recordType); +} + Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, Decl **Group, unsigned NumDecls) { @@ -4512,6 +5052,41 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, if (DS.isTypeSpecOwned()) Decls.push_back(DS.getRepAsDecl()); + // C++0x [dcl.spec.auto]p7: + // If the type deduced for the template parameter U is not the same in each + // deduction, the program is ill-formed. + // FIXME: When initializer-list support is added, a distinction is needed + // between the deduced type U and the deduced type which 'auto' stands for. + // auto a = 0, b = { 1, 2, 3 }; + // is legal because the deduced type U is 'int' in both cases. + bool TypeContainsAuto = DS.getTypeSpecType() == DeclSpec::TST_auto; + if (TypeContainsAuto && NumDecls > 1) { + QualType Deduced; + CanQualType DeducedCanon; + VarDecl *DeducedDecl = 0; + for (unsigned i = 0; i != NumDecls; ++i) { + if (VarDecl *D = dyn_cast<VarDecl>(Group[i])) { + AutoType *AT = D->getType()->getContainedAutoType(); + if (AT && AT->isDeduced()) { + QualType U = AT->getDeducedType(); + CanQualType UCanon = Context.getCanonicalType(U); + if (Deduced.isNull()) { + Deduced = U; + DeducedCanon = UCanon; + DeducedDecl = D; + } else if (DeducedCanon != UCanon) { + Diag(DS.getTypeSpecTypeLoc(), diag::err_auto_different_deductions) + << Deduced << DeducedDecl->getDeclName() + << U << D->getDeclName() + << DeducedDecl->getInit()->getSourceRange() + << D->getInit()->getSourceRange(); + break; + } + } + } + } + } + for (unsigned i = 0; i != NumDecls; ++i) if (Decl *D = Group[i]) Decls.push_back(D); @@ -4543,24 +5118,42 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { DiagnoseFunctionSpecifiers(D); - // Check that there are no default arguments inside the type of this - // parameter (C++ only). - if (getLangOptions().CPlusPlus) - CheckExtraCXXDefaultArguments(D); - TagDecl *OwnedDecl = 0; TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S, &OwnedDecl); QualType parmDeclType = TInfo->getType(); - if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) { - // C++ [dcl.fct]p6: - // Types shall not be defined in return or parameter types. - Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type) - << Context.getTypeDeclType(OwnedDecl); + if (getLangOptions().CPlusPlus) { + // Check that there are no default arguments inside the type of this + // parameter. + CheckExtraCXXDefaultArguments(D); + + if (OwnedDecl && OwnedDecl->isDefinition()) { + // C++ [dcl.fct]p6: + // Types shall not be defined in return or parameter types. + Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type) + << Context.getTypeDeclType(OwnedDecl); + } + + // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1). + if (D.getCXXScopeSpec().isSet()) { + Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator) + << D.getCXXScopeSpec().getRange(); + D.getCXXScopeSpec().clear(); + } + } + + // Ensure we have a valid name + IdentifierInfo *II = 0; + if (D.hasName()) { + II = D.getIdentifier(); + if (!II) { + Diag(D.getIdentifierLoc(), diag::err_bad_parameter_name) + << GetNameForDeclarator(D).getName().getAsString(); + D.setInvalidType(true); + } } // Check for redeclaration of parameters, e.g. int foo(int x, int x); - IdentifierInfo *II = D.getIdentifier(); if (II) { LookupResult R(*this, II, D.getIdentifierLoc(), LookupOrdinaryName, ForRedeclaration); @@ -4595,13 +5188,6 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { if (D.isInvalidType()) New->setInvalidDecl(); - // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1). - if (D.getCXXScopeSpec().isSet()) { - Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator) - << D.getCXXScopeSpec().getRange(); - New->setInvalidDecl(); - } - // Add the parameter declaration into this scope. S->AddDecl(New); if (II) @@ -4629,10 +5215,6 @@ ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC, void Sema::DiagnoseUnusedParameters(ParmVarDecl * const *Param, ParmVarDecl * const *ParamEnd) { - if (Diags.getDiagnosticLevel(diag::warn_unused_parameter) == - Diagnostic::Ignored) - return; - // Don't diagnose unused-parameter errors in template instantiations; we // will already have done so in the template itself. if (!ActiveTemplateInstantiations.empty()) @@ -4647,6 +5229,35 @@ void Sema::DiagnoseUnusedParameters(ParmVarDecl * const *Param, } } +void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param, + ParmVarDecl * const *ParamEnd, + QualType ReturnTy, + NamedDecl *D) { + if (LangOpts.NumLargeByValueCopy == 0) // No check. + return; + + // Warn if the return value is pass-by-value and larger than the specified + // threshold. + if (ReturnTy->isPODType()) { + unsigned Size = Context.getTypeSizeInChars(ReturnTy).getQuantity(); + if (Size > LangOpts.NumLargeByValueCopy) + Diag(D->getLocation(), diag::warn_return_value_size) + << D->getDeclName() << Size; + } + + // Warn if any parameter is pass-by-value and larger than the specified + // threshold. + for (; Param != ParamEnd; ++Param) { + QualType T = (*Param)->getType(); + if (!T->isPODType()) + continue; + unsigned Size = Context.getTypeSizeInChars(T).getQuantity(); + if (Size > LangOpts.NumLargeByValueCopy) + Diag((*Param)->getLocation(), diag::warn_parameter_size) + << (*Param)->getDeclName() << Size; + } +} + ParmVarDecl *Sema::CheckParameter(DeclContext *DC, TypeSourceInfo *TSInfo, QualType T, IdentifierInfo *Name, @@ -4688,9 +5299,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, SourceLocation LocAfterDecls) { - assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && - "Not a function declarator!"); - DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); // Verify 6.9.1p6: 'every identifier in the identifier list shall be declared' // for a K&R function. @@ -4724,14 +5333,7 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { assert(getCurFunctionDecl() == 0 && "Function parsing confused"); - assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && - "Not a function declarator!"); - DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; - - if (FTI.hasPrototype) { - // FIXME: Diagnose arguments without names in C. - } - + assert(D.isFunctionDeclarator() && "Not a function declarator!"); Scope *ParentScope = FnBodyScope->getParent(); Decl *DP = HandleDeclarator(ParentScope, D, @@ -4806,7 +5408,12 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { const FunctionDecl *Definition; if (FD->hasBody(Definition) && !canRedefineFunction(Definition, getLangOptions())) { - Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName(); + if (getLangOptions().GNUMode && Definition->isInlineSpecified() && + Definition->getStorageClass() == SC_Extern) + Diag(FD->getLocation(), diag::err_redefinition_extern_inline) + << FD->getDeclName() << getLangOptions().CPlusPlus; + else + Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName(); Diag(Definition->getLocation(), diag::note_previous_definition); } @@ -4839,10 +5446,8 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { PushDeclContext(FnBodyScope, FD); // Check the validity of our function parameters - CheckParmsForFunctionDef(FD); - - bool ShouldCheckShadow = - Diags.getDiagnosticLevel(diag::warn_decl_shadow) != Diagnostic::Ignored; + CheckParmsForFunctionDef(FD->param_begin(), FD->param_end(), + /*CheckParameterNames=*/true); // Introduce our parameters into the function scope for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { @@ -4851,8 +5456,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { // If this has an identifier, add it to the scope stack. if (Param->getIdentifier() && FnBodyScope) { - if (ShouldCheckShadow) - CheckShadow(FnBodyScope, Param); + CheckShadow(FnBodyScope, Param); PushOnScopeChains(Param, FnBodyScope); } @@ -4945,6 +5549,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (!FD->isInvalidDecl()) { DiagnoseUnusedParameters(FD->param_begin(), FD->param_end()); + DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(), + FD->getResultType(), FD); // If this is a constructor, we need a vtable. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD)) @@ -4957,55 +5563,18 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, } else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) { assert(MD == getCurMethodDecl() && "Method parsing confused"); MD->setBody(Body); - MD->setEndLoc(Body->getLocEnd()); - if (!MD->isInvalidDecl()) + if (Body) + MD->setEndLoc(Body->getLocEnd()); + if (!MD->isInvalidDecl()) { DiagnoseUnusedParameters(MD->param_begin(), MD->param_end()); + DiagnoseSizeOfParametersAndReturnValue(MD->param_begin(), MD->param_end(), + MD->getResultType(), MD); + } } else { return 0; } // Verify and clean out per-function state. - - // Check goto/label use. - FunctionScopeInfo *CurFn = getCurFunction(); - for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator - I = CurFn->LabelMap.begin(), E = CurFn->LabelMap.end(); I != E; ++I) { - LabelStmt *L = I->second; - - // Verify that we have no forward references left. If so, there was a goto - // or address of a label taken, but no definition of it. Label fwd - // definitions are indicated with a null substmt. - if (L->getSubStmt() != 0) - continue; - - // Emit error. - Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName(); - - // At this point, we have gotos that use the bogus label. Stitch it into - // the function body so that they aren't leaked and that the AST is well - // formed. - if (Body == 0) { - // The whole function wasn't parsed correctly. - continue; - } - - // Otherwise, the body is valid: we want to stitch the label decl into the - // function somewhere so that it is properly owned and so that the goto - // has a valid target. Do this by creating a new compound stmt with the - // label in it. - - // Give the label a sub-statement. - L->setSubStmt(new (Context) NullStmt(L->getIdentLoc())); - - CompoundStmt *Compound = isa<CXXTryStmt>(Body) ? - cast<CXXTryStmt>(Body)->getTryBlock() : - cast<CompoundStmt>(Body); - llvm::SmallVector<Stmt*, 64> Elements(Compound->body_begin(), - Compound->body_end()); - Elements.push_back(L); - Compound->setStmts(Context, Elements.data(), Elements.size()); - } - if (Body) { // C++ constructors that have function-try-blocks can't have return // statements in the handlers of that block. (C++ [except.handle]p14) @@ -5091,11 +5660,13 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, DeclSpec DS; unsigned DiagID; bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy, DiagID); - Error = Error; // Silence warning. + (void)Error; // Silence warning. assert(!Error && "Error setting up implicit decl!"); Declarator D(DS, Declarator::BlockContext); - D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0, - 0, 0, false, SourceLocation(), + D.AddTypeInfo(DeclaratorChunk::getFunction(ParsedAttributes(), + false, false, SourceLocation(), 0, + 0, 0, true, SourceLocation(), + false, SourceLocation(), false, 0,0,0, Loc, Loc, D), SourceLocation()); D.SetIdentifier(&II, Loc); @@ -5154,8 +5725,6 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context)); } - if (Context.BuiltinInfo.isNoReturn(BuiltinID)) - FD->setType(Context.getNoReturnType(FD->getType())); if (Context.BuiltinInfo.isNoThrow(BuiltinID)) FD->addAttr(::new (Context) NoThrowAttr(FD->getLocation(), Context)); if (Context.BuiltinInfo.isConst(BuiltinID)) @@ -5210,17 +5779,46 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, D.getIdentifier(), TInfo); - if (const TagType *TT = T->getAs<TagType>()) { - TagDecl *TD = TT->getDecl(); + // Bail out immediately if we have an invalid declaration. + if (D.isInvalidType()) { + NewTD->setInvalidDecl(); + return NewTD; + } + + // C++ [dcl.typedef]p8: + // If the typedef declaration defines an unnamed class (or + // enum), the first typedef-name declared by the declaration + // to be that class type (or enum type) is used to denote the + // class type (or enum type) for linkage purposes only. + // We need to check whether the type was declared in the declaration. + switch (D.getDeclSpec().getTypeSpecType()) { + case TST_enum: + case TST_struct: + case TST_union: + case TST_class: { + TagDecl *tagFromDeclSpec = cast<TagDecl>(D.getDeclSpec().getRepAsDecl()); + + // Do nothing if the tag is not anonymous or already has an + // associated typedef (from an earlier typedef in this decl group). + if (tagFromDeclSpec->getIdentifier()) break; + if (tagFromDeclSpec->getTypedefForAnonDecl()) break; + + // A well-formed anonymous tag must always be a TUK_Definition. + assert(tagFromDeclSpec->isThisDeclarationADefinition()); + + // The type must match the tag exactly; no qualifiers allowed. + if (!Context.hasSameType(T, Context.getTagDeclType(tagFromDeclSpec))) + break; - // If the TagDecl that the TypedefDecl points to is an anonymous decl - // keep track of the TypedefDecl. - if (!TD->getIdentifier() && !TD->getTypedefForAnonDecl()) - TD->setTypedefForAnonDecl(NewTD); + // Otherwise, set this is the anon-decl typedef for the tag. + tagFromDeclSpec->setTypedefForAnonDecl(NewTD); + break; + } + + default: + break; } - if (D.isInvalidType()) - NewTD->setInvalidDecl(); return NewTD; } @@ -5273,14 +5871,17 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, /// TagSpec indicates what kind of tag this is. TUK indicates whether this is a /// reference/declaration/definition of a tag. Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, CXXScopeSpec &SS, - IdentifierInfo *Name, SourceLocation NameLoc, - AttributeList *Attr, AccessSpecifier AS, - MultiTemplateParamsArg TemplateParameterLists, - bool &OwnedDecl, bool &IsDependent) { + SourceLocation KWLoc, CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, AccessSpecifier AS, + MultiTemplateParamsArg TemplateParameterLists, + bool &OwnedDecl, bool &IsDependent, + bool ScopedEnum, bool ScopedEnumUsesClassTag, + TypeResult UnderlyingType) { // If this is not a definition, it must have a name. assert((Name != 0 || TUK == TUK_Definition) && "Nameless record must be a definition!"); + assert(TemplateParameterLists.size() == 0 || TUK != TUK_Reference); OwnedDecl = false; TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); @@ -5289,11 +5890,16 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, bool isExplicitSpecialization = false; unsigned NumMatchedTemplateParamLists = TemplateParameterLists.size(); bool Invalid = false; - if (TUK != TUK_Reference) { + + // We only need to do this matching if we have template parameters + // or a scope specifier, which also conveniently avoids this work + // for non-C++ cases. + if (NumMatchedTemplateParamLists || + (SS.isNotEmpty() && TUK != TUK_Reference)) { if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier(KWLoc, SS, - (TemplateParameterList**)TemplateParameterLists.get(), - TemplateParameterLists.size(), + TemplateParameterLists.get(), + TemplateParameterLists.size(), TUK == TUK_Friend, isExplicitSpecialization, Invalid)) { @@ -5322,6 +5928,41 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } } + // Figure out the underlying type if this a enum declaration. We need to do + // this early, because it's needed to detect if this is an incompatible + // redeclaration. + llvm::PointerUnion<const Type*, TypeSourceInfo*> EnumUnderlying; + + if (Kind == TTK_Enum) { + if (UnderlyingType.isInvalid() || (!UnderlyingType.get() && ScopedEnum)) + // No underlying type explicitly specified, or we failed to parse the + // type, default to int. + EnumUnderlying = Context.IntTy.getTypePtr(); + else if (UnderlyingType.get()) { + // C++0x 7.2p2: The type-specifier-seq of an enum-base shall name an + // integral type; any cv-qualification is ignored. + TypeSourceInfo *TI = 0; + QualType T = GetTypeFromParser(UnderlyingType.get(), &TI); + EnumUnderlying = TI; + + SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc(); + + if (!T->isDependentType() && !T->isIntegralType(Context)) { + Diag(UnderlyingLoc, diag::err_enum_invalid_underlying) + << T; + // Recover by falling back to int. + EnumUnderlying = Context.IntTy.getTypePtr(); + } + + if (DiagnoseUnexpandedParameterPack(UnderlyingLoc, TI, + UPPC_FixedUnderlyingType)) + EnumUnderlying = Context.IntTy.getTypePtr(); + + } else if (getLangOptions().Microsoft) + // Microsoft enums are always of int type. + EnumUnderlying = Context.IntTy.getTypePtr(); + } + DeclContext *SearchDC = CurContext; DeclContext *DC = CurContext; bool isStdBadAlloc = false; @@ -5374,7 +6015,9 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // and that current instantiation has any dependent base // classes, we might find something at instantiation time: treat // this as a dependent elaborated-type-specifier. - if (Previous.wasNotFoundInCurrentInstantiation()) { + // But this only makes any sense for reference-like lookups. + if (Previous.wasNotFoundInCurrentInstantiation() && + (TUK == TUK_Reference || TUK == TUK_Friend)) { IsDependent = true; return 0; } @@ -5406,6 +6049,10 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, while (isa<RecordDecl>(SearchDC) || isa<EnumDecl>(SearchDC)) SearchDC = SearchDC->getParent(); } + } else if (S->isFunctionPrototypeScope()) { + // If this is an enum declaration in function prototype scope, set its + // initial context to the translation unit. + SearchDC = Context.getTranslationUnitDecl(); } if (Previous.isSingleResult() && @@ -5467,7 +6114,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // Find the context where we'll be declaring the tag. // FIXME: We would like to maintain the current DeclContext as the // lexical context, - while (SearchDC->isRecord()) + while (SearchDC->isRecord() || SearchDC->isTransparentContext()) SearchDC = SearchDC->getParent(); // Find the scope where we'll be declaring the tag. @@ -5554,6 +6201,41 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } } + if (Kind == TTK_Enum && PrevTagDecl->getTagKind() == TTK_Enum) { + const EnumDecl *PrevEnum = cast<EnumDecl>(PrevTagDecl); + + // All conflicts with previous declarations are recovered by + // returning the previous declaration. + if (ScopedEnum != PrevEnum->isScoped()) { + Diag(KWLoc, diag::err_enum_redeclare_scoped_mismatch) + << PrevEnum->isScoped(); + Diag(PrevTagDecl->getLocation(), diag::note_previous_use); + return PrevTagDecl; + } + else if (EnumUnderlying && PrevEnum->isFixed()) { + QualType T; + if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo*>()) + T = TI->getType(); + else + T = QualType(EnumUnderlying.get<const Type*>(), 0); + + if (!Context.hasSameUnqualifiedType(T, PrevEnum->getIntegerType())) { + Diag(NameLoc.isValid() ? NameLoc : KWLoc, + diag::err_enum_redeclare_type_mismatch) + << T + << PrevEnum->getIntegerType(); + Diag(PrevTagDecl->getLocation(), diag::note_previous_use); + return PrevTagDecl; + } + } + else if (!EnumUnderlying.isNull() != PrevEnum->isFixed()) { + Diag(KWLoc, diag::err_enum_redeclare_fixed_mismatch) + << PrevEnum->isFixed(); + Diag(PrevTagDecl->getLocation(), diag::note_previous_use); + return PrevTagDecl; + } + } + if (!Invalid) { // If this is a use, just return the declaration we found. @@ -5587,7 +6269,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } else { // If the type is currently being defined, complain // about a nested redefinition. - TagType *Tag = cast<TagType>(Context.getTagDeclType(PrevTagDecl)); + const TagType *Tag + = cast<TagType>(Context.getTagDeclType(PrevTagDecl)); if (Tag->isBeingDefined()) { Diag(NameLoc, diag::err_nested_redefinition) << Name; Diag(PrevTagDecl->getLocation(), @@ -5689,24 +6372,49 @@ CreateNewDecl: // PrevDecl. TagDecl *New; + bool IsForwardReference = false; if (Kind == TTK_Enum) { // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.: // enum X { A, B, C } D; D should chain to X. New = EnumDecl::Create(Context, SearchDC, Loc, Name, KWLoc, - cast_or_null<EnumDecl>(PrevDecl)); + cast_or_null<EnumDecl>(PrevDecl), ScopedEnum, + ScopedEnumUsesClassTag, !EnumUnderlying.isNull()); // If this is an undefined enum, warn. if (TUK != TUK_Definition && !Invalid) { TagDecl *Def; - if (PrevDecl && (Def = cast<EnumDecl>(PrevDecl)->getDefinition())) { + if (getLangOptions().CPlusPlus0x && cast<EnumDecl>(New)->isFixed()) { + // C++0x: 7.2p2: opaque-enum-declaration. + // Conflicts are diagnosed above. Do nothing. + } + else if (PrevDecl && (Def = cast<EnumDecl>(PrevDecl)->getDefinition())) { Diag(Loc, diag::ext_forward_ref_enum_def) << New; Diag(Def->getLocation(), diag::note_previous_definition); } else { - Diag(Loc, - getLangOptions().CPlusPlus? diag::err_forward_ref_enum - : diag::ext_forward_ref_enum); + unsigned DiagID = diag::ext_forward_ref_enum; + if (getLangOptions().Microsoft) + DiagID = diag::ext_ms_forward_ref_enum; + else if (getLangOptions().CPlusPlus) + DiagID = diag::err_forward_ref_enum; + Diag(Loc, DiagID); + + // If this is a forward-declared reference to an enumeration, make a + // note of it; we won't actually be introducing the declaration into + // the declaration context. + if (TUK == TUK_Reference) + IsForwardReference = true; } } + + if (EnumUnderlying) { + EnumDecl *ED = cast<EnumDecl>(New); + if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo*>()) + ED->setIntegerTypeSourceInfo(TI); + else + ED->setIntegerType(QualType(EnumUnderlying.get<const Type*>(), 0)); + ED->setPromotionType(ED->getIntegerType()); + } + } else { // struct/union/class @@ -5798,7 +6506,10 @@ CreateNewDecl: PushOnScopeChains(New, EnclosingScope, /* AddToContext = */ false); } else if (Name) { S = getNonFieldDeclScope(S); - PushOnScopeChains(New, S); + PushOnScopeChains(New, S, !IsForwardReference); + if (IsForwardReference) + SearchDC->makeDeclVisibleInContext(New, /* Recoverable = */ false); + } else { CurContext->addDecl(New); } @@ -5823,6 +6534,7 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { } void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, + ClassVirtSpecifiers &CVS, SourceLocation LBraceLoc) { AdjustDeclIfTemplate(TagD); CXXRecordDecl *Record = cast<CXXRecordDecl>(TagD); @@ -5832,6 +6544,11 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, if (!Record->getIdentifier()) return; + if (CVS.isFinalSpecified()) + Record->addAttr(new (Context) FinalAttr(CVS.getFinalLoc(), Context)); + if (CVS.isExplicitSpecified()) + Record->addAttr(new (Context) ExplicitAttr(CVS.getExplicitLoc(), Context)); + // C++ [class]p2: // [...] The class-name is also inserted into the scope of the // class itself; this is known as the injected-class-name. For @@ -5842,7 +6559,9 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, CurContext, Record->getLocation(), Record->getIdentifier(), Record->getTagKeywordLoc(), - Record); + /*PrevDecl=*/0, + /*DelayTypeCreation=*/true); + Context.getTypeDeclType(InjectedClassName, Record); InjectedClassName->setImplicit(); InjectedClassName->setAccess(AS_public); if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) @@ -5899,7 +6618,9 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, << FieldName << FieldTy << BitWidth->getSourceRange(); return Diag(FieldLoc, diag::err_not_integral_type_anon_bitfield) << FieldTy << BitWidth->getSourceRange(); - } + } else if (DiagnoseUnexpandedParameterPack(const_cast<Expr *>(BitWidth), + UPPC_BitFieldWidth)) + return true; // If the bit-width is type- or value-dependent, don't try to check // it now. @@ -5974,9 +6695,17 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType T = TInfo->getType(); - if (getLangOptions().CPlusPlus) + if (getLangOptions().CPlusPlus) { CheckExtraCXXDefaultArguments(D); + if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, + UPPC_DataMemberType)) { + D.setInvalidType(); + T = Context.IntTy; + TInfo = Context.getTrivialTypeSourceInfo(T, Loc); + } + } + DiagnoseFunctionSpecifiers(D); if (D.getDeclSpec().isThreadSpecified()) @@ -6128,35 +6857,27 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, } if (!InvalidDecl && getLangOptions().CPlusPlus) { - CXXRecordDecl* CXXRecord = cast<CXXRecordDecl>(Record); + if (Record->isUnion()) { + if (const RecordType *RT = EltTy->getAs<RecordType>()) { + CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl()); + if (RDecl->getDefinition()) { + // C++ [class.union]p1: An object of a class with a non-trivial + // constructor, a non-trivial copy constructor, a non-trivial + // destructor, or a non-trivial copy assignment operator + // cannot be a member of a union, nor can an array of such + // objects. + // TODO: C++0x alters this restriction significantly. + if (CheckNontrivialField(NewFD)) + NewFD->setInvalidDecl(); + } + } - if (!T->isPODType()) - CXXRecord->setPOD(false); - if (!ZeroWidth) - CXXRecord->setEmpty(false); - if (T->isReferenceType()) - CXXRecord->setHasTrivialConstructor(false); - - if (const RecordType *RT = EltTy->getAs<RecordType>()) { - CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl()); - if (RDecl->getDefinition()) { - if (!RDecl->hasTrivialConstructor()) - CXXRecord->setHasTrivialConstructor(false); - if (!RDecl->hasTrivialCopyConstructor()) - CXXRecord->setHasTrivialCopyConstructor(false); - if (!RDecl->hasTrivialCopyAssignment()) - CXXRecord->setHasTrivialCopyAssignment(false); - if (!RDecl->hasTrivialDestructor()) - CXXRecord->setHasTrivialDestructor(false); - - // C++ 9.5p1: An object of a class with a non-trivial - // constructor, a non-trivial copy constructor, a non-trivial - // destructor, or a non-trivial copy assignment operator - // cannot be a member of a union, nor can an array of such - // objects. - // TODO: C++0x alters this restriction significantly. - if (Record->isUnion() && CheckNontrivialField(NewFD)) - NewFD->setInvalidDecl(); + // C++ [class.union]p1: If a union contains a member of reference type, + // the program is ill-formed. + if (EltTy->isReferenceType()) { + Diag(NewFD->getLocation(), diag::err_union_member_of_reference_type) + << NewFD->getDeclName() << EltTy; + NewFD->setInvalidDecl(); } } } @@ -6171,18 +6892,6 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, Diag(Loc, diag::warn_attribute_weak_on_field); NewFD->setAccess(AS); - - // C++ [dcl.init.aggr]p1: - // An aggregate is an array or a class (clause 9) with [...] no - // private or protected non-static data members (clause 11). - // A POD must be an aggregate. - if (getLangOptions().CPlusPlus && - (AS == AS_private || AS == AS_protected)) { - CXXRecordDecl *CXXRecord = cast<CXXRecordDecl>(Record); - CXXRecord->setAggregate(false); - CXXRecord->setPOD(false); - } - return NewFD; } @@ -6532,7 +7241,7 @@ void Sema::ActOnFields(Scope* S, FieldDecl *FD = cast<FieldDecl>(Fields[i]); // Get the type for the field. - Type *FDTy = FD->getType().getTypePtr(); + const Type *FDTy = FD->getType().getTypePtr(); if (!FD->isAnonymousStructOrUnion()) { // Remember all fields written by the user. @@ -6563,10 +7272,22 @@ void Sema::ActOnFields(Scope* S, FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; - } else if (FDTy->isIncompleteArrayType() && i == NumFields - 1 && - Record && !Record->isUnion()) { + } else if (FDTy->isIncompleteArrayType() && Record && + ((i == NumFields - 1 && !Record->isUnion()) || + (getLangOptions().Microsoft && + (i == NumFields - 1 || Record->isUnion())))) { // Flexible array member. - if (NumNamedMembers < 1) { + // Microsoft is more permissive regarding flexible array. + // It will accept flexible array in union and also + // as the sole element of a struct/class. + if (getLangOptions().Microsoft) { + if (Record->isUnion()) + Diag(FD->getLocation(), diag::ext_flexible_array_union) + << FD->getDeclName(); + else if (NumFields == 1) + Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate) + << FD->getDeclName() << Record->getTagKind(); + } else if (NumNamedMembers < 1) { Diag(FD->getLocation(), diag::err_flexible_array_empty_struct) << FD->getDeclName(); FD->setInvalidDecl(); @@ -6581,7 +7302,6 @@ void Sema::ActOnFields(Scope* S, EnclosingDecl->setInvalidDecl(); continue; } - // Okay, we have a legal flexible array member at the end of the struct. if (Record) Record->setHasFlexibleArrayMember(true); @@ -6641,7 +7361,64 @@ void Sema::ActOnFields(Scope* S, // Okay, we successfully defined 'Record'. if (Record) { - Record->completeDefinition(); + bool Completed = false; + if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Record)) { + if (!CXXRecord->isInvalidDecl()) { + // Set access bits correctly on the directly-declared conversions. + UnresolvedSetImpl *Convs = CXXRecord->getConversionFunctions(); + for (UnresolvedSetIterator I = Convs->begin(), E = Convs->end(); + I != E; ++I) + Convs->setAccess(I, (*I)->getAccess()); + + if (!CXXRecord->isDependentType()) { + // Add any implicitly-declared members to this class. + AddImplicitlyDeclaredMembersToClass(CXXRecord); + + // If we have virtual base classes, we may end up finding multiple + // final overriders for a given virtual function. Check for this + // problem now. + if (CXXRecord->getNumVBases()) { + CXXFinalOverriderMap FinalOverriders; + CXXRecord->getFinalOverriders(FinalOverriders); + + for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(), + MEnd = FinalOverriders.end(); + M != MEnd; ++M) { + for (OverridingMethods::iterator SO = M->second.begin(), + SOEnd = M->second.end(); + SO != SOEnd; ++SO) { + assert(SO->second.size() > 0 && + "Virtual function without overridding functions?"); + if (SO->second.size() == 1) + continue; + + // C++ [class.virtual]p2: + // In a derived class, if a virtual member function of a base + // 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; + Diag(M->first->getLocation(), + diag::note_overridden_virtual_function); + for (OverridingMethods::overriding_iterator + OM = SO->second.begin(), + OMEnd = SO->second.end(); + OM != OMEnd; ++OM) + Diag(OM->Method->getLocation(), diag::note_final_overrider) + << (NamedDecl *)M->first << OM->Method->getParent(); + + Record->setInvalidDecl(); + } + } + CXXRecord->completeDefinition(&FinalOverriders); + Completed = true; + } + } + } + } + + if (!Completed) + Record->completeDefinition(); } else { ObjCIvarDecl **ClsFields = reinterpret_cast<ObjCIvarDecl**>(RecFields.data()); @@ -6695,9 +7472,11 @@ static bool isRepresentableIntegerValue(ASTContext &Context, assert(T->isIntegralType(Context) && "Integral type required!"); unsigned BitWidth = Context.getIntWidth(T); - if (Value.isUnsigned() || Value.isNonNegative()) - return Value.getActiveBits() < BitWidth; - + if (Value.isUnsigned() || Value.isNonNegative()) { + if (T->isSignedIntegerType()) + --BitWidth; + return Value.getActiveBits() <= BitWidth; + } return Value.getMinSignedBits() <= BitWidth; } @@ -6734,6 +7513,10 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, unsigned IntWidth = Context.Target.getIntWidth(); llvm::APSInt EnumVal(IntWidth); QualType EltTy; + + if (Val && DiagnoseUnexpandedParameterPack(Val, UPPC_EnumeratorValue)) + Val = 0; + if (Val) { if (Enum->isDependentType() || Val->isTypeDependent()) EltTy = Context.DependentTy; @@ -6761,12 +7544,30 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, } } - // C++0x [dcl.enum]p5: - // If the underlying type is not fixed, the type of each enumerator - // is the type of its initializing value: - // - If an initializer is specified for an enumerator, the - // initializing value has the same type as the expression. - EltTy = Val->getType(); + if (Enum->isFixed()) { + EltTy = Enum->getIntegerType(); + + // C++0x [dcl.enum]p5: + // ... if the initializing value of an enumerator cannot be + // represented by the underlying type, the program is ill-formed. + if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) { + if (getLangOptions().Microsoft) { + Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy; + ImpCastExprToType(Val, EltTy, CK_IntegralCast); + } else + Diag(IdLoc, diag::err_enumerator_too_large) + << EltTy; + } else + ImpCastExprToType(Val, EltTy, CK_IntegralCast); + } + else { + // C++0x [dcl.enum]p5: + // If the underlying type is not fixed, the type of each enumerator + // is the type of its initializing value: + // - If an initializer is specified for an enumerator, the + // initializing value has the same type as the expression. + EltTy = Val->getType(); + } } } } @@ -6783,7 +7584,12 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // // GCC uses 'int' for its unspecified integral type, as does // C99 6.7.2.2p3. - EltTy = Context.IntTy; + if (Enum->isFixed()) { + EltTy = Enum->getIntegerType(); + } + else { + EltTy = Context.IntTy; + } } else { // Assign the last value + 1. EnumVal = LastEnumConst->getInitVal(); @@ -6803,13 +7609,20 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // sufficient to contain the incremented value. If no such type // exists, the program is ill-formed. QualType T = getNextLargerIntegralType(Context, EltTy); - if (T.isNull()) { + if (T.isNull() || Enum->isFixed()) { // There is no integral type larger enough to represent this // value. Complain, then allow the value to wrap around. EnumVal = LastEnumConst->getInitVal(); - EnumVal.zext(EnumVal.getBitWidth() * 2); - Diag(IdLoc, diag::warn_enumerator_too_large) - << EnumVal.toString(10); + EnumVal = EnumVal.zext(EnumVal.getBitWidth() * 2); + ++EnumVal; + if (Enum->isFixed()) + // When the underlying type is fixed, this is ill-formed. + Diag(IdLoc, diag::err_enumerator_wrapped) + << EnumVal.toString(10) + << EltTy; + else + Diag(IdLoc, diag::warn_enumerator_too_large) + << EnumVal.toString(10); } else { EltTy = T; } @@ -6819,7 +7632,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // value, then increment. EnumVal = LastEnumConst->getInitVal(); EnumVal.setIsSigned(EltTy->isSignedIntegerType()); - EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); + EnumVal = EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); ++EnumVal; // If we're not in C++, diagnose the overflow of enumerator values, @@ -6841,7 +7654,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, if (!EltTy->isDependentType()) { // Make the enumerator value match the signedness and size of the // enumerator's type. - EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); + EnumVal = EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); EnumVal.setIsSigned(EltTy->isSignedIntegerType()); } @@ -6850,11 +7663,10 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, } -Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, - Decl *lastEnumConst, - SourceLocation IdLoc, - IdentifierInfo *Id, - SourceLocation EqualLoc, ExprTy *val) { +Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, + SourceLocation IdLoc, IdentifierInfo *Id, + AttributeList *Attr, + SourceLocation EqualLoc, ExprTy *val) { EnumDecl *TheEnumDecl = cast<EnumDecl>(theEnumDecl); EnumConstantDecl *LastEnumConst = cast_or_null<EnumConstantDecl>(lastEnumConst); @@ -6890,11 +7702,25 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, } } - EnumConstantDecl *New = CheckEnumConstant(TheEnumDecl, LastEnumConst, - IdLoc, Id, Val); + // C++ [class.mem]p13: + // If T is the name of a class, then each of the following shall have a + // name different from T: + // - every enumerator of every member of class T that is an enumerated + // type + if (CXXRecordDecl *Record + = dyn_cast<CXXRecordDecl>( + TheEnumDecl->getDeclContext()->getRedeclContext())) + if (Record->getIdentifier() && Record->getIdentifier() == Id) + Diag(IdLoc, diag::err_member_name_of_class) << Id; + + EnumConstantDecl *New = + CheckEnumConstant(TheEnumDecl, LastEnumConst, IdLoc, Id, Val); - // Register this decl in the current scope stack. if (New) { + // Process attributes. + if (Attr) ProcessDeclAttributeList(S, New, Attr); + + // Register this decl in the current scope stack. New->setAccess(TheEnumDecl->getAccess()); PushOnScopeChains(New, S); } @@ -6961,7 +7787,6 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, } // Figure out the type that should be used for this enum. - // FIXME: Support -fshort-enums. QualType BestType; unsigned BestWidth; @@ -6977,8 +7802,19 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, QualType BestPromotionType; bool Packed = Enum->getAttr<PackedAttr>() ? true : false; - - if (NumNegativeBits) { + // -fshort-enums is the equivalent to specifying the packed attribute on all + // enum definitions. + if (LangOpts.ShortEnums) + Packed = true; + + if (Enum->isFixed()) { + BestType = BestPromotionType = Enum->getIntegerType(); + // We don't need to set BestWidth, because BestType is going to be the type + // of the enumerators, but we do anyway because otherwise some compilers + // warn that it might be used uninitialized. + BestWidth = CharWidth; + } + else if (NumNegativeBits) { // If there is a negative value, figure out the smallest integer type (of // int/long/longlong) that fits. // If it's packed, check also if it fits a char or a short. @@ -7081,12 +7917,13 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, } // Adjust the APSInt value. - InitVal.extOrTrunc(NewWidth); + InitVal = InitVal.extOrTrunc(NewWidth); InitVal.setIsSigned(NewSign); ECD->setInitVal(InitVal); // Adjust the Expr initializer and type. - if (ECD->getInitExpr()) + if (ECD->getInitExpr() && + !Context.hasSameType(NewTy, ECD->getInitExpr()->getType())) ECD->setInitExpr(ImplicitCastExpr::Create(Context, NewTy, CK_IntegralCast, ECD->getInitExpr(), |