[cfe-commits] r153002 - in /cfe/trunk: include/clang/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplate.cpp test/CXX/class.access/p4.cpp test/CXX/dcl.decl/dcl.meaning/p1.cpp test/SemaCXX/nested-name-spec.cpp
Douglas Gregor
dgregor at apple.com
Sat Mar 17 16:06:31 PDT 2012
Author: dgregor
Date: Sat Mar 17 18:06:31 2012
New Revision: 153002
URL: http://llvm.org/viewvc/llvm-project?rev=153002&view=rev
Log:
Diagnose tag and class template declarations with qualified
declarator-ids that occur at class scope. Fixes PR8019.
Added:
cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1.cpp (with props)
Modified:
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/CXX/class.access/p4.cpp
cfe/trunk/test/SemaCXX/nested-name-spec.cpp
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=153002&r1=153001&r2=153002&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sat Mar 17 18:06:31 2012
@@ -1091,6 +1091,9 @@
const LookupResult &Previous,
Scope *S);
bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info);
+ bool diagnoseQualifiedDeclInClass(CXXScopeSpec &SS, DeclContext *DC,
+ DeclarationName Name,
+ SourceLocation Loc);
void DiagnoseFunctionSpecifiers(Declarator& D);
void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R);
void CheckShadow(Scope *S, VarDecl *D);
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=153002&r1=153001&r2=153002&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Mar 17 18:06:31 2012
@@ -3235,7 +3235,44 @@
return false;
}
+
+/// \brief Diagnose a declaration that has a qualified name within a class,
+/// which is ill-formed but often recoverable.
+///
+/// \returns true if we cannot safely recover from this error, false otherwise.
+bool Sema::diagnoseQualifiedDeclInClass(CXXScopeSpec &SS, DeclContext *DC,
+ DeclarationName Name,
+ SourceLocation Loc) {
+ // The user provided a superfluous scope specifier inside a class
+ // definition:
+ //
+ // class X {
+ // void X::f();
+ // };
+ if (CurContext->Equals(DC)) {
+ Diag(Loc, diag::warn_member_extra_qualification)
+ << Name << FixItHint::CreateRemoval(SS.getRange());
+ SS.clear();
+ return false;
+ }
+ Diag(Loc, diag::err_member_qualification)
+ << Name << SS.getRange();
+ SS.clear();
+
+ // C++ constructors and destructors with incorrect scopes can break
+ // our AST invariants by having the wrong underlying types. If
+ // that's the case, then drop this declaration entirely.
+ if ((Name.getNameKind() == DeclarationName::CXXConstructorName ||
+ Name.getNameKind() == DeclarationName::CXXDestructorName) &&
+ !Context.hasSameType(Name.getCXXNameType(),
+ Context.getTypeDeclType(
+ cast<CXXRecordDecl>(CurContext))))
+ return true;
+
+ return false;
+}
+
Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParamLists) {
// TODO: consider using NameInfo for diagnostic.
@@ -3294,31 +3331,9 @@
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();
-
- // C++ constructors and destructors with incorrect scopes can break
- // our AST invariants by having the wrong underlying types. If
- // that's the case, then drop this declaration entirely.
- if ((Name.getNameKind() == DeclarationName::CXXConstructorName ||
- Name.getNameKind() == DeclarationName::CXXDestructorName) &&
- !Context.hasSameType(Name.getCXXNameType(),
- Context.getTypeDeclType(cast<CXXRecordDecl>(CurContext))))
- return 0;
- }
-
- // Pretend that this qualifier was not here.
- D.getCXXScopeSpec().clear();
+ if (diagnoseQualifiedDeclInClass(D.getCXXScopeSpec(), DC,
+ Name, D.getIdentifierLoc()))
+ return 0;
}
}
@@ -8004,6 +8019,9 @@
<< SS.getRange();
return 0;
}
+
+ if (isa<CXXRecordDecl>(CurContext))
+ diagnoseQualifiedDeclInClass(SS, DC, Name, NameLoc);
}
if (RequireCompleteDeclContext(SS, DC))
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=153002&r1=153001&r2=153002&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Sat Mar 17 18:06:31 2012
@@ -886,7 +886,9 @@
ContextRAII SavedContext(*this, SemanticContext);
if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams))
Invalid = true;
- }
+ } else if (CurContext->isRecord() && TUK != TUK_Friend &&
+ TUK != TUK_Reference)
+ diagnoseQualifiedDeclInClass(SS, SemanticContext, Name, NameLoc);
LookupQualifiedName(Previous, SemanticContext);
} else {
@@ -1065,7 +1067,7 @@
PrevClassTemplate->setMemberSpecialization();
// Set the access specifier.
- if (!Invalid && TUK != TUK_Friend)
+ if (!Invalid && TUK != TUK_Friend && NewTemplate->getDeclContext()->isRecord())
SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
// Set the lexical context of these templates
Modified: cfe/trunk/test/CXX/class.access/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/p4.cpp?rev=153002&r1=153001&r2=153002&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.access/p4.cpp (original)
+++ cfe/trunk/test/CXX/class.access/p4.cpp Sat Mar 17 18:06:31 2012
@@ -481,7 +481,7 @@
};
template <class T> class A<T>::Inner {};
class B {
- template <class T> class A<T>::Inner;
+ template <class T> class A<T>::Inner; // expected-error{{non-friend class member 'Inner' cannot have a qualified name}}
};
void test() {
Added: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1.cpp?rev=153002&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1.cpp Sat Mar 17 18:06:31 2012
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace PR8019 {
+ struct x;
+ template<typename T> struct x2;
+ struct y {
+ struct PR8019::x { int x; }; // expected-error{{non-friend class member 'x' cannot have a qualified name}}
+
+ struct inner;
+ struct y::inner { }; // expected-warning{{extra qualification on member 'inner'}}
+
+ template<typename T>
+ struct PR8019::x2 { }; // expected-error{{non-friend class member 'x2' cannot have a qualified name}}
+
+ template<typename T>
+ struct inner_template;
+
+ template<typename T>
+ struct y::inner_template { }; // expected-warning{{extra qualification on member 'inner_template'}}
+ };
+
+}
Propchange: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: cfe/trunk/test/SemaCXX/nested-name-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nested-name-spec.cpp?rev=153002&r1=153001&r2=153002&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/nested-name-spec.cpp (original)
+++ cfe/trunk/test/SemaCXX/nested-name-spec.cpp Sat Mar 17 18:06:31 2012
@@ -274,7 +274,8 @@
protected:
struct B;
struct B::C; // expected-error {{requires a template parameter list}} \
- // expected-error {{no struct named 'C'}}
+ // expected-error {{no struct named 'C'}} \
+ // expected-error{{non-friend class member 'C' cannot have a qualified name}}
};
template<typename T>
More information about the cfe-commits
mailing list