diff --git a/clang/include/clang/Parse/DeclSpec.h b/clang/include/clang/Parse/DeclSpec.h index 1be687be8efe..e1f52a02466c 100644 --- a/clang/include/clang/Parse/DeclSpec.h +++ b/clang/include/clang/Parse/DeclSpec.h @@ -1017,8 +1017,8 @@ public: OverloadedOperatorKind getOverloadedOperator() const { return OperatorKind; } - void setInvalidType(bool flag) { InvalidType = flag; } - bool getInvalidType() const { + void setInvalidType(bool Val = true) { InvalidType = Val; } + bool isInvalidType() const { return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error; } diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 826845243084..f02b8a068255 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -37,7 +37,7 @@ Action::TypeResult Parser::ParseTypeName() { Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); ParseDeclarator(DeclaratorInfo); - if (DeclaratorInfo.getInvalidType()) + if (DeclaratorInfo.isInvalidType()) return true; return Actions.ActOnTypeName(CurScope, DeclaratorInfo); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index ec36fedc2d21..55bc1862f56f 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1338,7 +1338,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { SourceLocation Tmp = ParamInfo.getSourceRange().getEnd(); ParamInfo.SetIdentifier(0, CaretLoc); ParamInfo.SetRangeEnd(Tmp); - if (ParamInfo.getInvalidType()) { + if (ParamInfo.isInvalidType()) { // If there was an error parsing the arguments, they may have // tried to use ^(x+y) which requires an argument list. Just // skip the whole block literal. diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index f00edddffe5c..2f1b9c84d299 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -860,7 +860,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { } ParenTypeId = false; } - if (DeclaratorInfo.getInvalidType()) { + if (DeclaratorInfo.isInvalidType()) { SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); return ExprError(); } @@ -938,7 +938,7 @@ bool Parser::ParseExpressionListOrTypeId(ExprListTy &PlacementArgs, ParseSpecifierQualifierList(D.getMutableDeclSpec()); D.SetSourceRange(D.getDeclSpec().getSourceRange()); ParseDeclarator(D); - return D.getInvalidType(); + return D.isInvalidType(); } // It's not a type, it has to be an expression list. diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 7426965a4420..984576b5af29 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -326,7 +326,8 @@ public: // Type Analysis / Processing: SemaType.cpp. // QualType adjustParameterType(QualType T); - QualType ConvertDeclSpecToType(const DeclSpec &DS, SourceLocation DeclLoc); + QualType ConvertDeclSpecToType(const DeclSpec &DS, SourceLocation DeclLoc, + bool &IsInvalid); void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL); QualType BuildPointerType(QualType T, unsigned Quals, SourceLocation Loc, DeclarationName Entity); @@ -377,20 +378,18 @@ public: Scope *S); void DiagnoseFunctionSpecifiers(Declarator& D); NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, - Decl* PrevDecl, bool& InvalidDecl, + QualType R, Decl* PrevDecl, bool &Redeclaration); NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, - NamedDecl* PrevDecl, bool& InvalidDecl, + QualType R, NamedDecl* PrevDecl, bool &Redeclaration); - bool CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, + void CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, bool &Redeclaration); NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, NamedDecl* PrevDecl, bool IsFunctionDefinition, - bool& InvalidDecl, bool &Redeclaration); - bool CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, + bool &Redeclaration); + void CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, bool &Redeclaration, bool &OverloadableAttrRequired); virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D); @@ -518,10 +517,10 @@ public: /// Subroutines of ActOnDeclarator(). TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T); - bool MergeTypeDefDecl(TypedefDecl *New, Decl *Old); + void MergeTypeDefDecl(TypedefDecl *New, Decl *Old); bool MergeFunctionDecl(FunctionDecl *New, Decl *Old); bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old); - bool MergeVarDecl(VarDecl *New, Decl *Old); + void MergeVarDecl(VarDecl *New, Decl *Old); bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old); /// C++ Overloading. diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 9930dbc19bb5..64c85a2aad16 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -471,11 +471,16 @@ NamespaceDecl *Sema::GetStdNamespace() { /// MergeTypeDefDecl - We just parsed a typedef '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. Returns true if there was an error, -/// false otherwise. +/// diagnostics as appropriate. If there was an error, set New to be invalid. /// -bool Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { +void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { + // If either decl is known invalid already, set the new one to be invalid and + // don't bother doing any merging checks. + if (New->isInvalidDecl() || OldD->isInvalidDecl()) + return New->setInvalidDecl(); + bool objc_types = false; + // Allow multiple definitions for ObjC built-in typedefs. // FIXME: Verify the underlying types are equivalent! if (getLangOptions().ObjC1) { @@ -492,20 +497,17 @@ bool Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { if (!TypeID->isStr("Class")) break; Context.setObjCClassType(Context.getTypeDeclType(New)); - objc_types = true; - return false; + return; case 3: if (!TypeID->isStr("SEL")) break; Context.setObjCSelType(Context.getTypeDeclType(New)); - objc_types = true; - return false; + return; case 8: if (!TypeID->isStr("Protocol")) break; Context.setObjCProtoType(New->getUnderlyingType()); - objc_types = true; - return false; + return; } // Fall through - the typedef name was not a builtin type. } @@ -514,9 +516,9 @@ bool Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { if (!Old) { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); - if (!objc_types) + if (OldD->getLocation().isValid()) Diag(OldD->getLocation(), diag::note_previous_definition); - return true; + return New->setInvalidDecl(); } // Determine the "old" type we'll use for checking and diagnostics. @@ -534,12 +536,13 @@ bool Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { Context.getCanonicalType(New->getUnderlyingType())) { Diag(New->getLocation(), diag::err_redefinition_different_typedef) << New->getUnderlyingType() << OldType; - if (!objc_types) + if (Old->getLocation().isValid()) Diag(Old->getLocation(), diag::note_previous_definition); - return true; + return New->setInvalidDecl(); } - if (objc_types) return false; - if (getLangOptions().Microsoft) return false; + + if (objc_types || getLangOptions().Microsoft) + return; // C++ [dcl.typedef]p2: // In a given non-class scope, a typedef specifier can be used to @@ -547,11 +550,11 @@ bool Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { // to the type to which it already refers. if (getLangOptions().CPlusPlus) { if (!isa(CurContext)) - return false; + return; Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); - return true; + return New->setInvalidDecl(); } // If we have a redefinition of a typedef in C, emit a warning. This warning @@ -560,7 +563,7 @@ bool Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { Diag(New->getLocation(), diag::warn_redefinition_of_typedef) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); - return false; + return; } /// DeclhasAttr - returns true if decl Declaration already has the target @@ -883,14 +886,19 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { /// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative /// definitions here, since the initializer hasn't been attached. /// -bool Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { +void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { + // If either decl is invalid, make sure the new one is marked invalid and + // don't do any other checking. + if (New->isInvalidDecl() || OldD->isInvalidDecl()) + return New->setInvalidDecl(); + // Verify the old decl was also a variable. VarDecl *Old = dyn_cast(OldD); if (!Old) { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); Diag(OldD->getLocation(), diag::note_previous_definition); - return true; + return New->setInvalidDecl(); } MergeAttributes(New, Old, Context); @@ -901,7 +909,7 @@ bool Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { Diag(New->getLocation(), diag::err_redefinition_different_type) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); - return true; + return New->setInvalidDecl(); } New->setType(MergedT); @@ -910,7 +918,7 @@ bool Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { (Old->getStorageClass() == VarDecl::None || Old->hasExternalStorage())) { Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); - return true; + return New->setInvalidDecl(); } // C99 6.2.2p4: // For an identifier declared with the storage-class specifier @@ -927,7 +935,7 @@ bool Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { Old->getStorageClass() == VarDecl::Static) { Diag(New->getLocation(), diag::err_non_static_static) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); - return true; + return New->setInvalidDecl(); } // Variables with external linkage are analyzed in FinalizeDeclaratorGroup. @@ -940,7 +948,7 @@ bool Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { !New->getLexicalDeclContext()->isRecord())) { Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); - return true; + return New->setInvalidDecl(); } if (New->isThreadSpecified() && !Old->isThreadSpecified()) { @@ -953,8 +961,6 @@ bool Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { // Keep a chain of previous declarations. New->setPreviousDeclaration(Old); - - return false; } /// CheckParmsForFunctionDef - Check that the parameters of the given @@ -1337,7 +1343,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, bool IsFunctionDefinition) { // All of these full declarators require an identifier. If it doesn't have // one, the ParsedFreeStandingDeclSpec action should be used. if (!Name) { - if (!D.getInvalidType()) // Reject this if we think it is valid. + if (!D.isInvalidType()) // Reject this if we think it is valid. Diag(D.getDeclSpec().getSourceRange().getBegin(), diag::err_declarator_need_ident) << D.getDeclSpec().getSourceRange() << D.getSourceRange(); @@ -1353,11 +1359,10 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, bool IsFunctionDefinition) { DeclContext *DC; NamedDecl *PrevDecl; NamedDecl *New; - bool InvalidDecl = false; QualType R = GetTypeForDeclarator(D, S); if (R.isNull()) { - InvalidDecl = true; + D.setInvalidType(); R = Context.IntTy; if (IsFunctionDefinition) // int(...) R = Context.getFunctionType(R, 0, 0, true, 0); @@ -1368,7 +1373,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, bool IsFunctionDefinition) { if (D.getCXXScopeSpec().isInvalid()) { DC = CurContext; PrevDecl = 0; - InvalidDecl = true; + D.setInvalidType(); } else if (!D.getCXXScopeSpec().isSet()) { LookupNameKind NameKind = LookupOrdinaryName; @@ -1430,14 +1435,16 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, bool IsFunctionDefinition) { else Diag(L, diag::err_invalid_declarator_scope) << Name << cast(DC) << R; - InvalidDecl = true; + D.setInvalidType(); } } if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. - InvalidDecl = InvalidDecl - || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); + if (!D.isInvalidType()) + if (DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl)) + D.setInvalidType(); + // Just pretend that we didn't see the previous declaration. PrevDecl = 0; } @@ -1452,15 +1459,12 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, bool IsFunctionDefinition) { bool Redeclaration = false; if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { - New = ActOnTypedefDeclarator(S, D, DC, R, PrevDecl, - InvalidDecl, Redeclaration); + New = ActOnTypedefDeclarator(S, D, DC, R, PrevDecl, Redeclaration); } else if (R->isFunctionType()) { New = ActOnFunctionDeclarator(S, D, DC, R, PrevDecl, - IsFunctionDefinition, InvalidDecl, - Redeclaration); + IsFunctionDefinition, Redeclaration); } else { - New = ActOnVariableDeclarator(S, D, DC, R, PrevDecl, - InvalidDecl, Redeclaration); + New = ActOnVariableDeclarator(S, D, DC, R, PrevDecl, Redeclaration); } if (New == 0) @@ -1468,11 +1472,8 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, bool IsFunctionDefinition) { // If this has an identifier and is not an invalid redeclaration, // add it to the scope stack. - if (Name && !(Redeclaration && InvalidDecl)) + if (Name && !(Redeclaration && New->isInvalidDecl())) PushOnScopeChains(New, S); - // If any semantic error occurred, mark the decl as invalid. - if (D.getInvalidType() || InvalidDecl) - New->setInvalidDecl(); return DeclPtrTy::make(New); } @@ -1568,13 +1569,12 @@ void Sema::DiagnoseFunctionSpecifiers(Declarator& D) { NamedDecl* Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, Decl* PrevDecl, bool& InvalidDecl, - bool &Redeclaration) { + QualType R, Decl* PrevDecl, bool &Redeclaration) { // Typedef declarators cannot be qualified (C++ [dcl.meaning]p1). if (D.getCXXScopeSpec().isSet()) { Diag(D.getIdentifierLoc(), diag::err_qualified_typedef_declarator) << D.getCXXScopeSpec().getRange(); - InvalidDecl = true; + D.setInvalidType(); // Pretend we didn't see the scope specifier. DC = 0; } @@ -1591,6 +1591,9 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, TypedefDecl *NewTD = ParseTypedefDecl(S, D, R); if (!NewTD) return 0; + + if (D.isInvalidType()) + NewTD->setInvalidDecl(); // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(NewTD, D); @@ -1598,8 +1601,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, // in an outer scope, it isn't the same thing. if (PrevDecl && isDeclInScope(PrevDecl, DC, S)) { Redeclaration = true; - if (MergeTypeDefDecl(NewTD, PrevDecl)) - InvalidDecl = true; + MergeTypeDefDecl(NewTD, PrevDecl); } // C99 6.7.7p2: If a typedef name specifies a variably modified type @@ -1622,7 +1624,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, Diag(D.getIdentifierLoc(), diag::err_vla_decl_in_file_scope); else Diag(D.getIdentifierLoc(), diag::err_vm_decl_in_file_scope); - InvalidDecl = true; + NewTD->setInvalidDecl(); } } } @@ -1696,7 +1698,7 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC, NamedDecl* Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R,NamedDecl* PrevDecl, bool& InvalidDecl, + QualType R,NamedDecl* PrevDecl, bool &Redeclaration) { DeclarationName Name = GetNameForDeclarator(D); @@ -1718,7 +1720,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, // mutable can only appear on non-static class members, so it's always // an error here Diag(D.getIdentifierLoc(), diag::err_mutable_nonmember); - InvalidDecl = true; + D.setInvalidType(); SC = VarDecl::None; break; } @@ -1737,7 +1739,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, // appear in the declaration specifiers in an external declaration. if (SC == VarDecl::Auto || SC == VarDecl::Register) { Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope); - InvalidDecl = true; + D.setInvalidType(); } } if (DC->isRecord() && !CurContext->isRecord()) { @@ -1757,6 +1759,9 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, // FIXME: Move to DeclGroup... D.getDeclSpec().getSourceRange().getBegin()); + if (D.isInvalidType()) + NewVD->setInvalidDecl(); + if (D.getDeclSpec().isThreadSpecified()) { if (NewVD->hasLocalStorage()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global); @@ -1797,22 +1802,21 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, Diag(NewVD->getLocation(), diag::err_nonstatic_member_out_of_line) << D.getCXXScopeSpec().getRange(); PrevDecl = 0; - InvalidDecl = true; + NewVD->setInvalidDecl(); } } else if (D.getCXXScopeSpec().isSet()) { // No previous declaration in the qualifying scope. Diag(D.getIdentifierLoc(), diag::err_typecheck_no_member) << Name << D.getCXXScopeSpec().getRange(); - InvalidDecl = true; + NewVD->setInvalidDecl(); } - if (CheckVariableDeclaration(NewVD, PrevDecl, Redeclaration)) - InvalidDecl = true; + CheckVariableDeclaration(NewVD, PrevDecl, Redeclaration); // If this is a locally-scoped extern C variable, update the map of // such variables. if (CurContext->isFunctionOrMethod() && NewVD->isExternC(Context) && - !InvalidDecl) + !NewVD->isInvalidDecl()) RegisterLocallyScopedExternCDecl(NewVD, PrevDecl, S); return NewVD; @@ -1826,23 +1830,25 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, /// check variables after they have been parsed and their declarators /// have been translated into a declaration, and to check /// -/// \returns true if an error was encountered, false otherwise. -bool Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, +/// Sets NewVD->isInvalidDecl() if an error was encountered. +void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, bool &Redeclaration) { - bool Invalid = false; - + // If the decl is already known invalid, don't check it. + if (NewVD->isInvalidDecl()) + return; + QualType T = NewVD->getType(); if (T->isObjCInterfaceType()) { Diag(NewVD->getLocation(), diag::err_statically_allocated_object); - Invalid = true; + return NewVD->setInvalidDecl(); } // The variable can not have an abstract class type. if (RequireNonAbstractType(NewVD->getLocation(), T, diag::err_abstract_type_in_decl, AbstractVariableType)) - Invalid = true; + return NewVD->setInvalidDecl(); // Emit an error if an address space was applied to decl with local storage. // This includes arrays of objects with address space qualifiers, but not @@ -1850,7 +1856,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, // ISO/IEC TR 18037 S5.1.2 if (NewVD->hasLocalStorage() && (T.getAddressSpace() != 0)) { Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl); - Invalid = true; + return NewVD->setInvalidDecl(); } if (NewVD->hasLocalStorage() && T.isObjCGCWeak() @@ -1866,34 +1872,35 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, bool SizeIsNegative; QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative); - if (!FixedTy.isNull()) { - Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size); - NewVD->setType(FixedTy); - } else if (T->isVariableArrayType()) { - Invalid = true; - + + if (FixedTy.isNull() && T->isVariableArrayType()) { const VariableArrayType *VAT = Context.getAsVariableArrayType(T); // FIXME: This won't give the correct result for // int a[10][n]; SourceRange SizeRange = VAT->getSizeExpr()->getSourceRange(); - + if (NewVD->isFileVarDecl()) Diag(NewVD->getLocation(), diag::err_vla_decl_in_file_scope) - << SizeRange; + << SizeRange; else if (NewVD->getStorageClass() == VarDecl::Static) Diag(NewVD->getLocation(), diag::err_vla_decl_has_static_storage) - << SizeRange; + << SizeRange; else Diag(NewVD->getLocation(), diag::err_vla_decl_has_extern_linkage) - << SizeRange; - } else { - Invalid = true; - + << SizeRange; + return NewVD->setInvalidDecl(); + } + + if (FixedTy.isNull()) { if (NewVD->isFileVarDecl()) Diag(NewVD->getLocation(), diag::err_vm_decl_in_file_scope); else Diag(NewVD->getLocation(), diag::err_vm_decl_has_extern_linkage); + return NewVD->setInvalidDecl(); } + + Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size); + NewVD->setType(FixedTy); } if (!PrevDecl && NewVD->isExternC(Context)) { @@ -1906,26 +1913,22 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, PrevDecl = Pos->second; } - if (!Invalid && T->isVoidType() && !NewVD->hasExternalStorage()) { + if (T->isVoidType() && !NewVD->hasExternalStorage()) { Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type) << T; - Invalid = true; + return NewVD->setInvalidDecl(); } if (PrevDecl) { Redeclaration = true; - if (MergeVarDecl(NewVD, PrevDecl)) - Invalid = true; + MergeVarDecl(NewVD, PrevDecl); } - - return NewVD->isInvalidDecl() || Invalid; } NamedDecl* Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, NamedDecl* PrevDecl, - bool IsFunctionDefinition, - bool &InvalidDecl, bool &Redeclaration) { + bool IsFunctionDefinition, bool &Redeclaration) { assert(R.getTypePtr()->isFunctionType()); DeclarationName Name = GetNameForDeclarator(D); @@ -1937,7 +1940,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, case DeclSpec::SCS_mutable: Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_typecheck_sclass_func); - InvalidDecl = true; + D.setInvalidType(); break; case DeclSpec::SCS_unspecified: SC = FunctionDecl::None; break; case DeclSpec::SCS_extern: SC = FunctionDecl::Extern; break; @@ -1973,14 +1976,14 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, R->getAsFunctionType()->getResultType(), diag::err_abstract_type_in_decl, AbstractReturnType)) - InvalidDecl = true; + D.setInvalidType(); // Do not allow returning a objc interface by-value. if (R->getAsFunctionType()->getResultType()->isObjCInterfaceType()) { Diag(D.getIdentifierLoc(), diag::err_object_cannot_be_passed_returned_by_value) << 0 << R->getAsFunctionType()->getResultType(); - InvalidDecl = true; + D.setInvalidType(); } bool isVirtualOkay = false; @@ -1990,7 +1993,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, assert(DC->isRecord() && "Constructors can only be declared in a member context"); - InvalidDecl = InvalidDecl || CheckConstructorDeclarator(D, R, SC); + if (!D.isInvalidType()) + D.setInvalidType(CheckConstructorDeclarator(D, R, SC)); // Create the new declaration NewFD = CXXConstructorDecl::Create(Context, @@ -2001,8 +2005,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } else if (D.getKind() == Declarator::DK_Destructor) { // This is a C++ destructor declaration. if (DC->isRecord()) { - InvalidDecl = InvalidDecl || CheckDestructorDeclarator(D, R, SC); - + if (!D.isInvalidType()) + D.setInvalidType(CheckDestructorDeclarator(D, R, SC)); + NewFD = CXXDestructorDecl::Create(Context, cast(DC), D.getIdentifierLoc(), Name, R, @@ -2020,7 +2025,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, /*hasPrototype=*/true, // FIXME: Move to DeclGroup... D.getDeclSpec().getSourceRange().getBegin()); - InvalidDecl = true; + D.setInvalidType(); } } else if (D.getKind() == Declarator::DK_Conversion) { if (!DC->isRecord()) { @@ -2028,7 +2033,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, diag::err_conv_function_not_member); return 0; } else { - InvalidDecl = InvalidDecl || CheckConversionDeclarator(D, R, SC); + if (!D.isInvalidType()) + D.setInvalidType(CheckConversionDeclarator(D, R, SC)); NewFD = CXXConversionDecl::Create(Context, cast(DC), D.getIdentifierLoc(), Name, R, @@ -2062,7 +2068,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.getDeclSpec().getSourceRange().getBegin()); } - if (InvalidDecl) + if (D.isInvalidType()) NewFD->setInvalidDecl(); // Set the lexical context. If the declarator has a C++ @@ -2079,7 +2085,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // function is also virtual if it overrides an already virtual // function. This is important to do here because it's part of the // declaration. - if (isVirtual && !InvalidDecl) { + if (isVirtual && !NewFD->isInvalidDecl()) { if (!isVirtualOkay) { Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_non_function); @@ -2218,17 +2224,16 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Perform semantic checking on the function declaration. bool OverloadableAttrRequired = false; // FIXME: HACK! - if (CheckFunctionDeclaration(NewFD, PrevDecl, Redeclaration, - /*FIXME:*/OverloadableAttrRequired)) - InvalidDecl = true; + CheckFunctionDeclaration(NewFD, PrevDecl, Redeclaration, + /*FIXME:*/OverloadableAttrRequired); - if (D.getCXXScopeSpec().isSet() && !InvalidDecl) { + if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) { // An out-of-line member function declaration must also be a // definition (C++ [dcl.meaning]p1). if (!IsFunctionDefinition) { Diag(NewFD->getLocation(), diag::err_out_of_line_declaration) << D.getCXXScopeSpec().getRange(); - InvalidDecl = true; + NewFD->setInvalidDecl(); } else if (!Redeclaration) { // The user tried to provide an out-of-line definition for a // function that is a member of a class or namespace, but there @@ -2246,7 +2251,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // whether the parameter types are references). Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match) << cast(DC) << D.getCXXScopeSpec().getRange(); - InvalidDecl = true; + NewFD->setInvalidDecl(); LookupResult Prev = LookupQualifiedName(DC, Name, LookupOrdinaryName, true); @@ -2284,7 +2289,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // If this is a locally-scoped extern C function, update the // map of such names. if (CurContext->isFunctionOrMethod() && NewFD->isExternC(Context) - && !InvalidDecl) + && !NewFD->isInvalidDecl()) RegisterLocallyScopedExternCDecl(NewFD, PrevDecl, S); return NewFD; @@ -2300,18 +2305,21 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, /// that have been instantiated via C++ template instantiation (called /// via InstantiateDecl). /// -/// \returns true if there was an error, false otherwise. -bool Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, +/// This sets NewFD->isInvalidDecl() to true if there was an error. +void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, bool &Redeclaration, bool &OverloadableAttrRequired) { - bool InvalidDecl = false; + // If NewFD is already known erroneous, don't do any of this checking. + if (NewFD->isInvalidDecl()) + return; // Semantic checking for this function declaration (in isolation). if (getLangOptions().CPlusPlus) { // C++-specific checks. - if (CXXConstructorDecl *Constructor = dyn_cast(NewFD)) - InvalidDecl = InvalidDecl || CheckConstructor(Constructor); - else if (isa(NewFD)) { + if (CXXConstructorDecl *Constructor = dyn_cast(NewFD)) { + if (CheckConstructor(Constructor)) + return NewFD->setInvalidDecl(); + } else if (isa(NewFD)) { CXXRecordDecl *Record = cast(NewFD->getParent()); Record->setUserDeclaredDestructor(true); // C++ [class]p4: A POD-struct is an aggregate class that has [...] no @@ -2328,7 +2336,7 @@ bool Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, // Extra checking for C++ overloaded operators (C++ [over.oper]). if (NewFD->isOverloadedOperator() && CheckOverloadedOperatorDeclaration(NewFD)) - InvalidDecl = true; + return NewFD->setInvalidDecl(); } // C99 6.7.4p6: @@ -2386,7 +2394,6 @@ bool Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, if (!NewFD->getType()->getAsFunctionProtoType()) { Diag(NewFD->getLocation(), diag::err_attribute_overloadable_no_prototype) << NewFD; - InvalidDecl = true; Redeclaration = true; // Turn this into a variadic function with no parameters. @@ -2394,6 +2401,7 @@ bool Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, NewFD->getType()->getAsFunctionType()->getResultType(), 0, 0, true, 0); NewFD->setType(R); + return NewFD->setInvalidDecl(); } } @@ -2411,21 +2419,17 @@ bool Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, // NewFD and OldDecl represent declarations that need to be // merged. if (MergeFunctionDecl(NewFD, OldDecl)) - InvalidDecl = true; + return NewFD->setInvalidDecl(); - if (!InvalidDecl) - NewFD->setPreviousDeclaration(cast(OldDecl)); + NewFD->setPreviousDeclaration(cast(OldDecl)); } } - if (getLangOptions().CPlusPlus && !CurContext->isRecord()) { - // In C++, check default arguments now that we have merged decls. Unless - // the lexical context is the class, because in this case this is done - // during delayed parsing anyway. + // In C++, check default arguments now that we have merged decls. Unless + // the lexical context is the class, because in this case this is done + // during delayed parsing anyway. + if (getLangOptions().CPlusPlus && !CurContext->isRecord()) CheckCXXDefaultArguments(NewFD); - } - - return InvalidDecl || NewFD->isInvalidDecl(); } bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { @@ -2798,9 +2802,6 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { if (getLangOptions().CPlusPlus) CheckExtraCXXDefaultArguments(D); - // In this context, we *do not* check D.getInvalidType(). If the declarator - // type was invalid, GetTypeForDeclarator() still returns a "valid" type, - // though it will not reflect the user specified type. QualType parmDeclType = GetTypeForDeclarator(D, S); if (parmDeclType.isNull()) { D.setInvalidType(true); @@ -2850,7 +2851,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { D.getIdentifierLoc(), II, T, parmDeclType, StorageClass, 0); - if (D.getInvalidType()) + if (D.isInvalidType()) New->setInvalidDecl(); // Parameter declarators cannot be interface types. All ObjC objects are @@ -3210,7 +3211,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T) { TD->setTypedefForAnonDecl(NewTD); } - if (D.getInvalidType()) + if (D.isInvalidType()) NewTD->setInvalidDecl(); return NewTD; } @@ -3712,6 +3713,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, Declarator *D) { IdentifierInfo *II = Name.getAsIdentifierInfo(); bool InvalidDecl = false; + if (D) InvalidDecl = D->isInvalidType(); // If we receive a broken type, recover by assuming 'int' and // marking this declaration as invalid. @@ -3753,6 +3755,8 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, BitWidth, Mutable); + if (InvalidDecl) + NewFD->setInvalidDecl(); if (PrevDecl && !isa(PrevDecl)) { Diag(Loc, diag::err_duplicate_member) << II; @@ -3772,9 +3776,6 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, if (T.isObjCGCWeak()) Diag(Loc, diag::warn_attribute_weak_on_field); - if (InvalidDecl) - NewFD->setInvalidDecl(); - NewFD->setAccess(AS); // C++ [dcl.init.aggr]p1: @@ -3820,16 +3821,15 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, // example, unnamed unions inject all members into the struct namespace! QualType T = GetTypeForDeclarator(D, S); - bool InvalidDecl = D.getInvalidType(); - if (T.isNull()) { - InvalidDecl = true; - T = Context.IntTy; - } + if (T.isNull()) { + D.setInvalidType(); + T = Context.IntTy; + } if (BitWidth) { // 6.7.2.1p3, 6.7.2.1p4 if (VerifyBitField(Loc, II, T, BitWidth)) { - InvalidDecl = true; + D.setInvalidType(); DeleteExpr(BitWidth); BitWidth = 0; } @@ -3844,7 +3844,7 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, // than a variably modified type. if (T->isVariablyModifiedType()) { Diag(Loc, diag::err_typecheck_ivar_variable_size); - InvalidDecl = true; + D.setInvalidType(); } // Get the visibility (access control) for this ivar. @@ -3869,7 +3869,7 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, // Process attributes attached to the ivar. ProcessDeclAttributes(NewID, D); - if (D.getInvalidType() || InvalidDecl) + if (D.isInvalidType()) NewID->setInvalidDecl(); if (II) { diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 82830ef4ad6f..e3a0063b0d8b 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2547,7 +2547,7 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { QualType ExDeclType = GetTypeForDeclarator(D, S); SourceLocation Begin = D.getDeclSpec().getSourceRange().getBegin(); - bool Invalid = false; + bool Invalid = D.isInvalidType(); // Arrays and functions decay. if (ExDeclType->isArrayType()) @@ -2597,15 +2597,15 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { VarDecl *ExDecl = VarDecl::Create(Context, CurContext, D.getIdentifierLoc(), II, ExDeclType, VarDecl::None, Begin); - if (D.getInvalidType() || Invalid) - ExDecl->setInvalidDecl(); - - if (D.getCXXScopeSpec().isSet()) { + if (D.getCXXScopeSpec().isSet() && !Invalid) { Diag(D.getIdentifierLoc(), diag::err_qualified_catch_declarator) << D.getCXXScopeSpec().getRange(); - ExDecl->setInvalidDecl(); + Invalid = true; } + if (Invalid) + ExDecl->setInvalidDecl(); + // Add the exception declaration into this scope. S->AddDecl(DeclPtrTy::make(ExDecl)); if (II) diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 753fd5efc1bb..6b0c04440a8c 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -243,7 +243,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, } QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, Skip); - if (D.getInvalidType()) + if (D.isInvalidType()) return ExprError(); if (CheckAllocatedType(AllocType, D)) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 4639511023c6..d7e81127a753 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -124,9 +124,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // FIXME: In theory, we could have a previous declaration for // variables that are not static data members. bool Redeclaration = false; - if (SemaRef.CheckVariableDeclaration(Var, 0, Redeclaration)) - Var->setInvalidDecl(); - + SemaRef.CheckVariableDeclaration(Var, 0, Redeclaration); Owner->addDecl(SemaRef.Context, Var); if (D->getInit()) { @@ -322,9 +320,8 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { PrevDecl = 0; bool Redeclaration = false; bool OverloadableAttrRequired = false; - if (SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration, - /*FIXME:*/OverloadableAttrRequired)) - Method->setInvalidDecl(); + SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration, + /*FIXME:*/OverloadableAttrRequired); if (!Method->isInvalidDecl() || !PrevDecl) Owner->addDecl(SemaRef.Context, Method); @@ -366,12 +363,10 @@ Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) { PrevDecl = 0; bool Redeclaration = false; bool OverloadableAttrRequired = false; - if (SemaRef.CheckFunctionDeclaration(Constructor, PrevDecl, Redeclaration, - /*FIXME:*/OverloadableAttrRequired)) - Constructor->setInvalidDecl(); + SemaRef.CheckFunctionDeclaration(Constructor, PrevDecl, Redeclaration, + /*FIXME:*/OverloadableAttrRequired); - if (!Constructor->isInvalidDecl()) - Owner->addDecl(SemaRef.Context, Constructor); + Owner->addDecl(SemaRef.Context, Constructor); return Constructor; } @@ -396,9 +391,8 @@ Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) { bool Redeclaration = false; bool OverloadableAttrRequired = false; NamedDecl *PrevDecl = 0; - if (SemaRef.CheckFunctionDeclaration(Destructor, PrevDecl, Redeclaration, - /*FIXME:*/OverloadableAttrRequired)) - Destructor->setInvalidDecl(); + SemaRef.CheckFunctionDeclaration(Destructor, PrevDecl, Redeclaration, + /*FIXME:*/OverloadableAttrRequired); Owner->addDecl(SemaRef.Context, Destructor); return Destructor; } @@ -426,9 +420,8 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) { bool Redeclaration = false; bool OverloadableAttrRequired = false; NamedDecl *PrevDecl = 0; - if (SemaRef.CheckFunctionDeclaration(Conversion, PrevDecl, Redeclaration, - /*FIXME:*/OverloadableAttrRequired)) - Conversion->setInvalidDecl(); + SemaRef.CheckFunctionDeclaration(Conversion, PrevDecl, Redeclaration, + /*FIXME:*/OverloadableAttrRequired); Owner->addDecl(SemaRef.Context, Conversion); return Conversion; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 62d2489b3458..7519aff630a8 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -50,7 +50,8 @@ QualType Sema::adjustParameterType(QualType T) { /// \returns The type described by the declaration specifiers, or NULL /// if there was an error. QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, - SourceLocation DeclLoc) { + SourceLocation DeclLoc, + bool &isInvalid) { // FIXME: Should move the logic from DeclSpec::Finish to here for validity // checking. QualType Result; @@ -205,8 +206,15 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, DeclLoc = DS.getSourceRange().getBegin(); Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) << DS.getSourceRange(); + isInvalid = true; } } + + // If this is a reference to an invalid typedef, propagate the invalidity. + if (TypedefType *TDT = dyn_cast(Result)) + if (TDT->getDecl()->isInvalidDecl()) + isInvalid = true; + // TypeQuals handled by caller. break; } @@ -614,9 +622,12 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) { // the first return statement. T = Context.DependentTy; } else { - T = ConvertDeclSpecToType(DS, D.getIdentifierLoc()); + bool isInvalid = false; + T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid); if (T.isNull()) return T; + if (isInvalid) + D.setInvalidType(true); } break; } diff --git a/clang/test/Sema/invalid-decl.c b/clang/test/Sema/invalid-decl.c index e9130c80a90e..8c458008cb5c 100644 --- a/clang/test/Sema/invalid-decl.c +++ b/clang/test/Sema/invalid-decl.c @@ -6,11 +6,14 @@ void test() { // PR2400 -typedef xtype (*zend_stream_fsizer_t)(void* handle); // expected-error {{function cannot return array or function type}} expected-warning {{type specifier missing, defaults to 'int'}} expected-warning {{type specifier missing, defaults to 'int'}} +typedef xtype (*x)(void* handle); // expected-error {{function cannot return array or function type}} expected-warning {{type specifier missing, defaults to 'int'}} expected-warning {{type specifier missing, defaults to 'int'}} + +typedef void ytype(); + typedef struct _zend_module_entry zend_module_entry; struct _zend_module_entry { - xtype globals_size; // expected-error {{field 'globals_size' declared as a function}} + ytype globals_size; // expected-error {{field 'globals_size' declared as a function}} }; zend_module_entry openssl_module_entry = { diff --git a/clang/test/Sema/tentative-decls.c b/clang/test/Sema/tentative-decls.c index 85b5ed76bd6b..e3c893c77718 100644 --- a/clang/test/Sema/tentative-decls.c +++ b/clang/test/Sema/tentative-decls.c @@ -23,8 +23,8 @@ int i1 = 1; // expected-note {{previous definition is here}} int i1 = 2; // expected-error {{redefinition of 'i1'}} int i1; int i1; -extern int i1; // expected-note {{previous definition is here}} -static int i1; // expected-error{{static declaration of 'i1' follows non-static declaration}} +extern int i5; // expected-note {{previous definition is here}} +static int i5; // expected-error{{static declaration of 'i5' follows non-static declaration}} static int i2 = 5; // expected-note 1 {{previous definition is here}} int i2 = 3; // expected-error{{non-static declaration of 'i2' follows static declaration}} @@ -47,8 +47,8 @@ int redef[]; // expected-note {{previous definition is here}} int redef[11]; // expected-error{{redefinition of 'redef'}} void func() { - extern int i1; // expected-note {{previous definition is here}} - static int i1; // expected-error{{static declaration of 'i1' follows non-static declaration}} + extern int i6; // expected-note {{previous definition is here}} + static int i6; // expected-error{{static declaration of 'i6' follows non-static declaration}} } void func2(void) diff --git a/clang/test/SemaCXX/constructor-recovery.cpp b/clang/test/SemaCXX/constructor-recovery.cpp index f2f9f43a10d4..50fdc9622e4c 100644 --- a/clang/test/SemaCXX/constructor-recovery.cpp +++ b/clang/test/SemaCXX/constructor-recovery.cpp @@ -1,9 +1,10 @@ // RUN: clang-cc -fsyntax-only -verify %s -struct C { - virtual C() = 0; // expected-error{{constructor cannot be declared 'virtual'}} +struct C { // expected-note {{candidate function}} + virtual C() = 0; // expected-error{{constructor cannot be declared 'virtual'}} \ + expected-note {{candidate function}} }; void f() { - C c; + C c; // expected-error {{call to constructor of 'c' is ambiguous}} } diff --git a/clang/test/SemaCXX/destructor.cpp b/clang/test/SemaCXX/destructor.cpp index 3ba5fd594662..c60045bb59d1 100644 --- a/clang/test/SemaCXX/destructor.cpp +++ b/clang/test/SemaCXX/destructor.cpp @@ -23,6 +23,7 @@ struct D { // expected-error{{destructor cannot be variadic}} }; + struct E; typedef E E_typedef;