Justin Bogner <[email protected]> writes:
> Justin Bogner <[email protected]> writes:
>> Richard Smith <[email protected]> writes:
>>> On Tue, Jun 30, 2015 at 5:32 PM, Justin Bogner <[email protected]>
>>> wrote:
>>>> Richard Smith <[email protected]> writes:
>>>>> On Tue, Jun 30, 2015 at 4:57 PM, Justin Bogner
>>>>> <[email protected]> wrote:
>>>>>> + if (Name && !isAcceptableTagRedeclaration(PrevTagDecl, Kind,
>>>>>> + TUK == TUK_Definition, KWLoc,
>>>>>> + *Name)) {
>>>>>
>>>>> So, this is tricky: if SafeToContinue is false, we don't want to
>>>>> carry on because we'd make an EnumDecl a redeclaration of a
>>>>> RecordDecl or vicer versa, which would violate the AST
>>>>> invariants. I'm not sure how we get here from error recovery:
>>>>> both places that set Name to nullptr also jump past this code.
>>>>> I think the only way to reach this is if SkipBody->Previous is
>>>>> non-null, in which case this is not error recovery and we should
>>>>> perform this check.
>>>>>
>>>>> Can you instead change isAcceptableTagRedeclaration to take a
>>>>> const IdentifierInfo*?
>>>>
>>>> The IdentifierInfo is only used in a diagnostic - I think it makes sense
>>>> to pass `OrigName` here if we want the check. This is what we do a
>>>> little below for diagnoseQualifiedDeclaration().
>>>
>>> But OrigName is null too, isn't it? The only places that make Name and
>>> OrigName differ also jump past this code.
>>
>> You're right - I misread the assert where OrigName is assigned and was
>> confused.
>>
>> I don't think passing const IdentifierInfo* is correct -
>> isAcceptableTagRedeclaration implements [dcl.type.elab]p3, which is
>> about elaborated-type-specifiers with the same name agreeing on kind.
>> It doesn't make much sense to do this check if there isn't a name at
>> all, and it seems suspicious to me that we're getting here at all.
>>
>> What does !Previous.empty() mean if we don't have a Name?
>>
>> This behaviour only triggers on one test in the test suite,
>> test/Modules/submodules-merge-defs.cpp. You can reproduce with
>> assert(Name) before the call to isAcceptableTagRedeclaration() if you're
>> curious.
>
> FWIW, we're no longer hitting the UB here as of r241763 - I believe
> r241743 is the relevant commit. It's not totally clear to me whether
> that fixed or hid the bug though.
Sorry, I was wrong about this, but now I understand how we get here.
This fires when we're merging anonymous enum definitions (as per
r236690). We're merging an enum like the following with a definition
we've already seen:
enum { f, g, h };
In this case, it's perfectly reasonable to not have a name and we do
want to check that the redecl is compatible, so I've gone with the
"const IdentifierInfo *" solution, attached. Okay to commit?
On a side note, passing null pointers to `operator<<(const
DiagnosticBuilder, const IdentifierInfo)` eventually leads to this code:
case DiagnosticsEngine::ak_identifierinfo: {
const IdentifierInfo *II = getArgIdentifier(ArgNo);
assert(ModifierLen == 0 && "No modifiers for strings yet");
// Don't crash if get passed a null pointer by accident.
if (!II) {
const char *S = "(null)";
OutStr.append(S, S + strlen(S));
continue;
}
llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\'';
break;
}
Here, the comment claims that passing a null pointer is an accident, but
we seem to do it intentionally (at least, a few tests fail if I change
it to an assert). Is the comment wrong, or should we look into fixing
that?
commit 700b866ff0b5d65007a836dd0cbcf800d326f4b2
Author: Justin Bogner <[email protected]>
Date: Fri Jul 10 14:41:48 2015 -0700
Sema: Allow null names to be passed in to isAcceptableTagRedeclaration
It's possible for TagRedeclarations to involve decls without a name,
ie, anonymous enums. We hit some undefined behaviour if we bind these
null names to the reference here.
We never dereference the name, so it's harmless if it's null - make it
a pointer to allow that.
Fixes the Modules/submodules-merge-defs.cpp test under ubsan.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index b5a1b0b..ca06b21 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1849,7 +1849,7 @@ public:
bool isAcceptableTagRedeclaration(const TagDecl *Previous,
TagTypeKind NewTag, bool isDefinition,
SourceLocation NewTagLoc,
- const IdentifierInfo &Name);
+ const IdentifierInfo *Name);
enum TagUseKind {
TUK_Reference, // Reference to a tag: 'struct foo *X;'
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 9db14bf..2887721 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -11294,7 +11294,7 @@ static bool isClassCompatTagKind(TagTypeKind Tag)
bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
TagTypeKind NewTag, bool isDefinition,
SourceLocation NewTagLoc,
- const IdentifierInfo &Name) {
+ const IdentifierInfo *Name) {
// C++ [dcl.type.elab]p3:
// The class-key or enum keyword present in the
// elaborated-type-specifier shall agree in kind with the
@@ -11323,7 +11323,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
// In a template instantiation, do not offer fix-its for tag mismatches
// since they usually mess up the template instead of fixing the problem.
Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
- << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name
+ << getRedeclDiagFromTagKind(NewTag) << isTemplate << Name
<< getRedeclDiagFromTagKind(OldTag);
return true;
}
@@ -11342,7 +11342,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
if (!previousMismatch) {
previousMismatch = true;
Diag(NewTagLoc, diag::warn_struct_class_previous_tag_mismatch)
- << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name
+ << getRedeclDiagFromTagKind(NewTag) << isTemplate << Name
<< getRedeclDiagFromTagKind(I->getTagKind());
}
Diag(I->getInnerLocStart(), diag::note_struct_class_suggestion)
@@ -11364,7 +11364,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
}
Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
- << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name
+ << getRedeclDiagFromTagKind(NewTag) << isTemplate << Name
<< getRedeclDiagFromTagKind(OldTag);
Diag(Redecl->getLocation(), diag::note_previous_use);
@@ -11847,7 +11847,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// struct or something similar.
if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind,
TUK == TUK_Definition, KWLoc,
- *Name)) {
+ Name)) {
bool SafeToContinue
= (PrevTagDecl->getTagKind() != TTK_Enum &&
Kind != TTK_Enum);
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 97904ce..035c37c 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1008,7 +1008,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// template declaration (7.1.5.3).
RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl();
if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind,
- TUK == TUK_Definition, KWLoc, *Name)) {
+ TUK == TUK_Definition, KWLoc, Name)) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< Name
<< FixItHint::CreateReplacement(KWLoc, PrevRecordDecl->getKindName());
@@ -2310,7 +2310,7 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
assert(Id && "templated class must have an identifier");
if (!isAcceptableTagRedeclaration(D, TagKind, TUK == TUK_Definition,
- TagLoc, *Id)) {
+ TagLoc, Id)) {
Diag(TagLoc, diag::err_use_with_wrong_tag)
<< Result
<< FixItHint::CreateReplacement(SourceRange(TagLoc), D->getKindName());
@@ -6199,7 +6199,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
assert(Kind != TTK_Enum && "Invalid enum tag in class template spec!");
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
Kind, TUK == TUK_Definition, KWLoc,
- *ClassTemplate->getIdentifier())) {
+ ClassTemplate->getIdentifier())) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< ClassTemplate
<< FixItHint::CreateReplacement(KWLoc,
@@ -7235,7 +7235,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
Kind, /*isDefinition*/false, KWLoc,
- *ClassTemplate->getIdentifier())) {
+ ClassTemplate->getIdentifier())) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< ClassTemplate
<< FixItHint::CreateReplacement(KWLoc,
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 7d58017..c1961e5 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -989,7 +989,7 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc,
if (Id && Keyword != ETK_None && Keyword != ETK_Typename) {
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword);
if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, /*isDefinition*/false,
- TagLocation, *Id)) {
+ 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 8b150c3..6e193a3 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1010,7 +1010,7 @@ public:
}
if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, /*isDefinition*/false,
- IdLoc, *Id)) {
+ IdLoc, Id)) {
SemaRef.Diag(KeywordLoc, diag::err_use_with_wrong_tag) << Id;
SemaRef.Diag(Tag->getLocation(), diag::note_previous_use);
return QualType();
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits