Hi rjmccall, rsmith,
Following patch fixes crash in clang with attached test case [taken from
g++.old-deja/g++.other/using3.C].
Issue:
Test is trying to make using declaration for a non-existing member in
base class in derived class and expect error
while compiling. Current clang code handles normal cases properly.
Problem arises when base class is typedefed to a type constructed
in-place. As using declaration is referring to a
non-existing member, normal lookup fails and while trying
typo-correction, clang returns typedef declaration as
possible alternative, which is not a record type and can not be type
casted to EnumDecl/ RecordDecl/ CXXRecordDecl.
But Sema::CheckUsingShadowDecl() assumes otherwise and tries to
typecast it to CXXRecordDecl without any check while
checking if referred type is from base class or not. This results in
crash in clang.
Solution:
I looked for ways to get CXXRecordDecl from TypedefDecl but did not
find any. I found function like getUnderlyingDecl()
but they just work with UsingDecls and ObjCCompatibleAliasDecls.
Moreover, for any existing member, clang find proper
declaration and code works fine.
So I have added a check in Sema::CheckUsingShadowDecl() to bypass base
class check if referred type in using declaration
is not in a record type. A proper fix will be if we can get proper
RecordDecl from TypedefDecl and use it for this check
or handle TypedefDecl case separately.
http://llvm-reviews.chandlerc.com/D3051
Files:
lib/Sema/SemaDeclCXX.cpp
test/SemaCXX/using-decl-2.cpp
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -7164,28 +7164,29 @@
if (!getLangOpts().CPlusPlus11 && CurContext->isRecord()) {
DeclContext *OrigDC = Orig->getDeclContext();
- // Handle enums and anonymous structs.
+ if (OrigDC->isRecord()) {
+ // Handle enums and anonymous structs.
if (isa<EnumDecl>(OrigDC)) OrigDC = OrigDC->getParent();
- CXXRecordDecl *OrigRec = cast<CXXRecordDecl>(OrigDC);
- while (OrigRec->isAnonymousStructOrUnion())
- OrigRec = cast<CXXRecordDecl>(OrigRec->getDeclContext());
+ CXXRecordDecl *OrigRec = cast<CXXRecordDecl>(OrigDC);
+ while (OrigRec->isAnonymousStructOrUnion())
+ OrigRec = cast<CXXRecordDecl>(OrigRec->getDeclContext());
+
+ if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom(OrigRec)) {
+ if (OrigDC == CurContext) {
+ Diag(Using->getLocation(),
+ diag::err_using_decl_nested_name_specifier_is_current_class)
+ << Using->getQualifierLoc().getSourceRange();
+ Diag(Orig->getLocation(), diag::note_using_decl_target);
+ return true;
+ }
- if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom(OrigRec)) {
- if (OrigDC == CurContext) {
- Diag(Using->getLocation(),
- diag::err_using_decl_nested_name_specifier_is_current_class)
- << Using->getQualifierLoc().getSourceRange();
+ Diag(Using->getQualifierLoc().getBeginLoc(),
+ diag::err_using_decl_nested_name_specifier_is_not_base_class)
+ << Using->getQualifier() << cast<CXXRecordDecl>(CurContext)
+ << Using->getQualifierLoc().getSourceRange();
Diag(Orig->getLocation(), diag::note_using_decl_target);
return true;
}
-
- Diag(Using->getQualifierLoc().getBeginLoc(),
- diag::err_using_decl_nested_name_specifier_is_not_base_class)
- << Using->getQualifier()
- << cast<CXXRecordDecl>(CurContext)
- << Using->getQualifierLoc().getSourceRange();
- Diag(Orig->getLocation(), diag::note_using_decl_target);
- return true;
}
}
Index: test/SemaCXX/using-decl-2.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/using-decl-2.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct A {
+ A();
+};
+
+typedef struct {
+ A i;
+} S; // expected-note {{declared here}}
+
+struct B : S {
+ using S::S; // expected-error {{no member named 'S' in 'S'}}
+};
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -7164,28 +7164,29 @@
if (!getLangOpts().CPlusPlus11 && CurContext->isRecord()) {
DeclContext *OrigDC = Orig->getDeclContext();
- // Handle enums and anonymous structs.
+ if (OrigDC->isRecord()) {
+ // Handle enums and anonymous structs.
if (isa<EnumDecl>(OrigDC)) OrigDC = OrigDC->getParent();
- CXXRecordDecl *OrigRec = cast<CXXRecordDecl>(OrigDC);
- while (OrigRec->isAnonymousStructOrUnion())
- OrigRec = cast<CXXRecordDecl>(OrigRec->getDeclContext());
+ CXXRecordDecl *OrigRec = cast<CXXRecordDecl>(OrigDC);
+ while (OrigRec->isAnonymousStructOrUnion())
+ OrigRec = cast<CXXRecordDecl>(OrigRec->getDeclContext());
+
+ if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom(OrigRec)) {
+ if (OrigDC == CurContext) {
+ Diag(Using->getLocation(),
+ diag::err_using_decl_nested_name_specifier_is_current_class)
+ << Using->getQualifierLoc().getSourceRange();
+ Diag(Orig->getLocation(), diag::note_using_decl_target);
+ return true;
+ }
- if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom(OrigRec)) {
- if (OrigDC == CurContext) {
- Diag(Using->getLocation(),
- diag::err_using_decl_nested_name_specifier_is_current_class)
- << Using->getQualifierLoc().getSourceRange();
+ Diag(Using->getQualifierLoc().getBeginLoc(),
+ diag::err_using_decl_nested_name_specifier_is_not_base_class)
+ << Using->getQualifier() << cast<CXXRecordDecl>(CurContext)
+ << Using->getQualifierLoc().getSourceRange();
Diag(Orig->getLocation(), diag::note_using_decl_target);
return true;
}
-
- Diag(Using->getQualifierLoc().getBeginLoc(),
- diag::err_using_decl_nested_name_specifier_is_not_base_class)
- << Using->getQualifier()
- << cast<CXXRecordDecl>(CurContext)
- << Using->getQualifierLoc().getSourceRange();
- Diag(Orig->getLocation(), diag::note_using_decl_target);
- return true;
}
}
Index: test/SemaCXX/using-decl-2.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/using-decl-2.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct A {
+ A();
+};
+
+typedef struct {
+ A i;
+} S; // expected-note {{declared here}}
+
+struct B : S {
+ using S::S; // expected-error {{no member named 'S' in 'S'}}
+};
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits