diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 70 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 3 |
4 files changed, 72 insertions, 14 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 1adc8bd0ed..9967fd3ebf 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -6599,7 +6599,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, /// /// \returns true if the new tag kind is acceptable, false otherwise. bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, - TagTypeKind NewTag, + TagTypeKind NewTag, bool isDefinition, SourceLocation NewTagLoc, const IdentifierInfo &Name) { // C++ [dcl.type.elab]p3: @@ -6616,8 +6616,9 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, // struct class-key shall be used to refer to a class (clause 9) // declared using the class or struct class-key. TagTypeKind OldTag = Previous->getTagKind(); - if (OldTag == NewTag) - return true; + if (!isDefinition || (NewTag != TTK_Class && NewTag != TTK_Struct)) + if (OldTag == NewTag) + return true; if ((OldTag == TTK_Struct || OldTag == TTK_Class) && (NewTag == TTK_Struct || NewTag == TTK_Class)) { @@ -6626,12 +6627,63 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous)) isTemplate = Record->getDescribedClassTemplate(); + if (!ActiveTemplateInstantiations.empty()) { + // In a template instantiation, do not offer fix-its for tag mismatches + // since they usually mess up the template instead of fixing the problem. + Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) + << (NewTag == TTK_Class) << isTemplate << &Name; + return true; + } + + if (isDefinition) { + // On definitions, check previous tags and issue a fix-it for each + // one that doesn't match the current tag. + if (Previous->getDefinition()) { + // Don't suggest fix-its for redefinitions. + return true; + } + + bool previousMismatch = false; + for (TagDecl::redecl_iterator I(Previous->redecls_begin()), + E(Previous->redecls_end()); I != E; ++I) { + if (I->getTagKind() != NewTag) { + if (!previousMismatch) { + previousMismatch = true; + Diag(NewTagLoc, diag::warn_struct_class_previous_tag_mismatch) + << (NewTag == TTK_Class) << isTemplate << &Name; + } + Diag(I->getInnerLocStart(), diag::note_struct_class_suggestion) + << (NewTag == TTK_Class) + << FixItHint::CreateReplacement(I->getInnerLocStart(), + NewTag == TTK_Class? + "class" : "struct"); + } + } + return true; + } + + // Check for a previous definition. If current tag and definition + // are same type, do nothing. If no definition, but disagree with + // with previous tag type, give a warning, but no fix-it. + const TagDecl *Redecl = Previous->getDefinition() ? + Previous->getDefinition() : Previous; + if (Redecl->getTagKind() == NewTag) { + return true; + } + Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) << (NewTag == TTK_Class) - << isTemplate << &Name - << FixItHint::CreateReplacement(SourceRange(NewTagLoc), - OldTag == TTK_Class? "class" : "struct"); - Diag(Previous->getLocation(), diag::note_previous_use); + << isTemplate << &Name; + Diag(Redecl->getLocation(), diag::note_previous_use); + + // If there is a previous defintion, suggest a fix-it. + if (Previous->getDefinition()) { + Diag(NewTagLoc, diag::note_struct_class_suggestion) + << (Redecl->getTagKind() == TTK_Class) + << FixItHint::CreateReplacement(SourceRange(NewTagLoc), + Redecl->getTagKind() == TTK_Class? "class" : "struct"); + } + return true; } return false; @@ -6957,7 +7009,9 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, isDeclInScope(PrevDecl, SearchDC, S, isExplicitSpecialization)) { // Make sure that this wasn't declared as an enum and now used as a // struct or something similar. - if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) { + if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, + TUK == TUK_Definition, KWLoc, + *Name)) { bool SafeToContinue = (PrevTagDecl->getTagKind() != TTK_Enum && Kind != TTK_Enum); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 8213f3266f..5d4caacd81 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -920,7 +920,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // the class-key shall agree in kind with the original class // template declaration (7.1.5.3). RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl(); - if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, KWLoc, *Name)) { + if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, + TUK == TUK_Definition, KWLoc, *Name)) { Diag(KWLoc, diag::err_use_with_wrong_tag) << Name << FixItHint::CreateReplacement(KWLoc, PrevRecordDecl->getKindName()); @@ -2130,7 +2131,8 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, IdentifierInfo *Id = D->getIdentifier(); assert(Id && "templated class must have an identifier"); - if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) { + if (!isAcceptableTagRedeclaration(D, TagKind, TUK == TUK_Definition, + TagLoc, *Id)) { Diag(TagLoc, diag::err_use_with_wrong_tag) << Result << FixItHint::CreateReplacement(SourceRange(TagLoc), D->getKindName()); @@ -4775,7 +4777,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); assert(Kind != TTK_Enum && "Invalid enum tag in class template spec!"); if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), - Kind, KWLoc, + Kind, TUK == TUK_Definition, KWLoc, *ClassTemplate->getIdentifier())) { Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate @@ -5746,7 +5748,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, assert(Kind != TTK_Enum && "Invalid enum tag in class template explicit instantiation!"); if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), - Kind, KWLoc, + Kind, /*isDefinition*/false, KWLoc, *ClassTemplate->getIdentifier())) { Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 907a7e24a9..444fb9a2f2 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -927,7 +927,8 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc, // like it's likely to produce a lot of spurious errors. if (Keyword != ETK_None && Keyword != ETK_Typename) { TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword); - if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, TagLocation, *Id)) { + if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, /*isDefinition*/false, + TagLocation, *Id)) { SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag) << Id << FixItHint::CreateReplacement(SourceRange(TagLocation), diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 06017e7cba..245499e8a1 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -879,7 +879,8 @@ public: return QualType(); } - if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, IdLoc, *Id)) { + if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, /*isDefinition*/false, + IdLoc, *Id)) { SemaRef.Diag(KeywordLoc, diag::err_use_with_wrong_tag) << Id; SemaRef.Diag(Tag->getLocation(), diag::note_previous_use); return QualType(); |