From f1f9b4e5c7fd087e78f2e387c01098d49d41e784 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 3 Nov 2008 15:51:28 +0000 Subject: [PATCH] Implement C++ DR 106 and C++ DR 540, both of which deal with reference-collapsing. Implement diagnostic for formation of a reference to cv void. Drop cv-qualifiers added to a reference type when the reference type comes from a typedef. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58612 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticKinds.def | 6 ++-- lib/Parse/ParseDecl.cpp | 13 +++++++ lib/Sema/SemaType.cpp | 47 +++++++++++++++++++++---- test/SemaCXX/references.cpp | 12 +++++++ 4 files changed, 69 insertions(+), 9 deletions(-) diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index b240cea77a..db4f2f4c93 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -657,8 +657,6 @@ DIAG(ext_anon_param_requires_type_specifier, EXTENSION, DIAG(err_missing_param, ERROR, "expected parameter declarator") -DIAG(err_invalid_reference_qualifier_application, ERROR, - "'%0' qualifier may not be applied to a reference") DIAG(err_declarator_need_ident, ERROR, "declarator requires an identifier") DIAG(err_bad_language, ERROR, @@ -959,6 +957,10 @@ DIAG(err_illegal_decl_pointer_to_reference, ERROR, "'%0' declared as a pointer to a reference") DIAG(err_illegal_decl_reference_to_reference, ERROR, "'%0' declared as a reference to a reference") +DIAG(err_invalid_reference_qualifier_application, ERROR, + "'%0' qualifier may not be applied to a reference") +DIAG(err_reference_to_void, ERROR, + "cannot form a reference to 'void'") DIAG(err_qualified_block_pointer_type, ERROR, "qualifier specification on block pointer type not allowed") DIAG(err_nonfunction_block_type, ERROR, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 7a84171a05..f414f16af7 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1222,6 +1222,19 @@ void Parser::ParseDeclaratorInternal(Declarator &D) { // Recursively parse the declarator. ParseDeclaratorInternal(D); + if (D.getNumTypeObjects() > 0) { + // C++ [dcl.ref]p4: There shall be no references to references. + DeclaratorChunk& InnerChunk = D.getTypeObject(D.getNumTypeObjects() - 1); + if (InnerChunk.Kind == DeclaratorChunk::Reference) { + Diag(InnerChunk.Loc, diag::err_illegal_decl_reference_to_reference, + D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); + + // Once we've complained about the reference-to-referwnce, we + // can go ahead and build the (technically ill-formed) + // declarator: reference collapsing will take care of it. + } + } + // Remember that we parsed a reference type. It doesn't have type-quals. D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc, DS.TakeAttributes())); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 93f182c27e..85c57f53ad 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -232,6 +232,17 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS) { Result.getAsString(), DS.getSourceRange()); } + // C++ [dcl.ref]p1: + // Cv-qualified references are ill-formed except when the + // cv-qualifiers are introduced through the use of a typedef + // (7.1.3) or of a template type argument (14.3), in which + // case the cv-qualifiers are ignored. + if (DS.getTypeSpecType() == DeclSpec::TST_typedef && + TypeQuals && Result->isReferenceType()) { + TypeQuals &= ~QualType::Const; + TypeQuals &= ~QualType::Volatile; + } + Result = Result.getQualifiedType(TypeQuals); } return Result; @@ -283,13 +294,33 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { // Apply the pointer typequals to the pointer object. T = Context.getPointerType(T).getQualifiedType(DeclType.Ptr.TypeQuals); break; - case DeclaratorChunk::Reference: - if (const ReferenceType *RT = T->getAsReferenceType()) { - // C++ 8.3.2p4: There shall be no references to references. - Diag(DeclType.Loc, diag::err_illegal_decl_reference_to_reference, - D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); + case DeclaratorChunk::Reference: { + // Whether we should suppress the creation of the reference. + bool SuppressReference = false; + if (T->isReferenceType()) { + // C++ [dcl.ref]p4: There shall be no references to references. + // + // According to C++ DR 106, references to references are only + // diagnosed when they are written directly (e.g., "int & &"), + // but not when they happen via a typedef: + // + // typedef int& intref; + // typedef intref& intref2; + // + // Parser::ParserDeclaratorInternal diagnoses the case where + // references are written directly; here, we handle the + // collapsing of references-to-references as described in C++ + // DR 106 and amended by C++ DR 540. + SuppressReference = true; + } + + // C++ [dcl.ref]p1: + // A declarator that specifies the type “reference to cv void” + // is ill-formed. + if (T->isVoidType()) { + Diag(DeclType.Loc, diag::err_reference_to_void); D.setInvalidType(true); - T = RT->getPointeeType(); + T = Context.IntTy; } // Enforce C99 6.7.3p2: "Types other than pointer types derived from @@ -302,12 +333,14 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { DeclType.Ref.HasRestrict = false; } - T = Context.getReferenceType(T); + if (!SuppressReference) + T = Context.getReferenceType(T); // Handle restrict on references. if (DeclType.Ref.HasRestrict) T.addRestrict(); break; + } case DeclaratorChunk::Array: { DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr; Expr *ArraySize = static_cast(ATI.NumElts); diff --git a/test/SemaCXX/references.cpp b/test/SemaCXX/references.cpp index a127f77c27..ca58db57ef 100644 --- a/test/SemaCXX/references.cpp +++ b/test/SemaCXX/references.cpp @@ -75,3 +75,15 @@ struct C : B, A { }; void test7(C& c) { A& a1 = c; // expected-error {{ambiguous conversion from derived class 'struct C' to base class 'struct A':}} } + +// C++ [dcl.ref]p1, C++ [dcl.ref]p4 +void test8(int& const,// expected-error{{'const' qualifier may not be applied to a reference}} + + void&, // expected-error{{cannot form a reference to 'void'}} + int& &) // expected-error{{'type name' declared as a reference to a reference}} +{ + typedef int& intref; + typedef intref& intrefref; // C++ DR 106: reference collapsing + + typedef intref const intref_c; // okay. FIXME: how do we verify that this is the same type as intref? +} -- 2.50.1