diff options
Diffstat (limited to 'lib/Sema/SemaType.cpp')
-rw-r--r-- | lib/Sema/SemaType.cpp | 232 |
1 files changed, 123 insertions, 109 deletions
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 51e1fb06e2..b402d3f2da 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1789,8 +1789,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, if (D.getAttributes()) distributeTypeAttrsFromDeclarator(state, T); - // C++0x [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context. - // In C++0x, a function declarator using 'auto' must have a trailing return + // C++11 [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context. + // In C++11, a function declarator using 'auto' must have a trailing return // type (this is checked later) and we can skip this. In other languages // using auto, we need to check regardless. if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && @@ -1852,7 +1852,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, if (D.isFunctionDeclarator()) Error = 10; - // C++0x [dcl.spec.auto]p2: 'auto' is always fine if the declarator + // C++11 [dcl.spec.auto]p2: 'auto' is always fine if the declarator // contains a trailing return type. That is only legal at the outermost // level. Check all declarator chunks (outermost first) anyway, to give // better diagnostics. @@ -1893,7 +1893,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case Declarator::ForContext: case Declarator::BlockLiteralContext: case Declarator::LambdaExprContext: - // C++0x [dcl.type]p3: + // C++11 [dcl.type]p3: // A type-specifier-seq shall not define a class or enumeration unless // it appears in the type-id of an alias-declaration (7.1.3) that is not // the declaration of a template-declaration. @@ -1937,6 +1937,66 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, return T; } +std::string getFunctionQualifiersAsString(const FunctionProtoType *FnTy) { + std::string Quals = + Qualifiers::fromCVRMask(FnTy->getTypeQuals()).getAsString(); + + switch (FnTy->getRefQualifier()) { + case RQ_None: + break; + + case RQ_LValue: + if (!Quals.empty()) + Quals += ' '; + Quals += '&'; + break; + + case RQ_RValue: + if (!Quals.empty()) + Quals += ' '; + Quals += "&&"; + break; + } + + return Quals; +} + +/// Check that the function type T, which has a cv-qualifier or a ref-qualifier, +/// can be contained within the declarator chunk DeclType, and produce an +/// appropriate diagnostic if not. +static void checkQualifiedFunction(Sema &S, QualType T, + DeclaratorChunk &DeclType) { + // C++98 [dcl.fct]p4 / C++11 [dcl.fct]p6: a function type with a + // cv-qualifier or a ref-qualifier can only appear at the topmost level + // of a type. + int DiagKind = -1; + switch (DeclType.Kind) { + case DeclaratorChunk::Paren: + case DeclaratorChunk::MemberPointer: + // These cases are permitted. + return; + case DeclaratorChunk::Array: + case DeclaratorChunk::Function: + // These cases don't allow function types at all; no need to diagnose the + // qualifiers separately. + return; + case DeclaratorChunk::BlockPointer: + DiagKind = 0; + break; + case DeclaratorChunk::Pointer: + DiagKind = 1; + break; + case DeclaratorChunk::Reference: + DiagKind = 2; + break; + } + + assert(DiagKind != -1); + S.Diag(DeclType.Loc, diag::err_compound_qualified_function_type) + << DiagKind << isa<FunctionType>(T.IgnoreParens()) << T + << getFunctionQualifiersAsString(T->castAs<FunctionProtoType>()); +} + static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, QualType declSpecType, TypeSourceInfo *TInfo) { @@ -1968,6 +2028,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, D.getContext() == Declarator::AliasDeclContext || D.getContext() == Declarator::AliasTemplateContext; + // Does T refer to a function type with a cv-qualifier or a ref-qualifier? + bool IsQualifiedFunction = T->isFunctionProtoType() && + (T->castAs<FunctionProtoType>()->getTypeQuals() != 0 || + T->castAs<FunctionProtoType>()->getRefQualifier() != RQ_None); + // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). @@ -1975,6 +2040,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, unsigned chunkIndex = e - i - 1; state.setCurrentChunkIndex(chunkIndex); DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex); + if (IsQualifiedFunction) { + checkQualifiedFunction(S, T, DeclType); + IsQualifiedFunction = DeclType.Kind == DeclaratorChunk::Paren; + } switch (DeclType.Kind) { case DeclaratorChunk::Paren: T = S.BuildParenType(T); @@ -2056,6 +2125,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // does not have a K&R-style identifier list), then the arguments are part // of the type, otherwise the argument list is (). const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; + IsQualifiedFunction = FTI.TypeQuals || FTI.hasRefQualifier(); // Check for auto functions and trailing return type and adjust the // return type accordingly. @@ -2407,113 +2477,57 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, FnTy->getNumArgs(), EPI); } - // C++0x [dcl.fct]p6: - // A ref-qualifier shall only be part of the function type for a - // non-static member function, the function type to which a pointer to - // member refers, or the top-level function type of a function typedef - // declaration. - if ((FnTy->getTypeQuals() != 0 || FnTy->getRefQualifier()) && - !(D.getContext() == Declarator::TemplateTypeArgContext && - !D.isFunctionDeclarator()) && !IsTypedefName && - (FreeFunction || - D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) { - if (D.getContext() == Declarator::TemplateTypeArgContext) { - // Accept qualified function types as template type arguments as a GNU - // extension. This is also the subject of C++ core issue 547. - std::string Quals; - if (FnTy->getTypeQuals() != 0) - Quals = Qualifiers::fromCVRMask(FnTy->getTypeQuals()).getAsString(); - - switch (FnTy->getRefQualifier()) { - case RQ_None: - break; - - case RQ_LValue: - if (!Quals.empty()) - Quals += ' '; - Quals += '&'; - break; - - case RQ_RValue: - if (!Quals.empty()) - Quals += ' '; - Quals += "&&"; - break; - } - - S.Diag(D.getIdentifierLoc(), - diag::ext_qualified_function_type_template_arg) - << Quals; - } else { - if (FnTy->getTypeQuals() != 0) { - if (D.isFunctionDeclarator()) { - SourceRange Range = D.getIdentifierLoc(); - for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) { - const DeclaratorChunk &Chunk = D.getTypeObject(N-I-1); - if (Chunk.Kind == DeclaratorChunk::Function && - Chunk.Fun.TypeQuals != 0) { - switch (Chunk.Fun.TypeQuals) { - case Qualifiers::Const: - Range = Chunk.Fun.getConstQualifierLoc(); - break; - case Qualifiers::Volatile: - Range = Chunk.Fun.getVolatileQualifierLoc(); - break; - case Qualifiers::Const | Qualifiers::Volatile: { - SourceLocation CLoc = Chunk.Fun.getConstQualifierLoc(); - SourceLocation VLoc = Chunk.Fun.getVolatileQualifierLoc(); - if (S.getSourceManager() - .isBeforeInTranslationUnit(CLoc, VLoc)) { - Range = SourceRange(CLoc, VLoc); - } else { - Range = SourceRange(VLoc, CLoc); - } - } - break; - } - break; - } - } - S.Diag(Range.getBegin(), diag::err_invalid_qualified_function_type) - << FixItHint::CreateRemoval(Range); - } else - S.Diag(D.getIdentifierLoc(), - diag::err_invalid_qualified_typedef_function_type_use) - << FreeFunction; - } - - if (FnTy->getRefQualifier()) { - if (D.isFunctionDeclarator()) { - SourceLocation Loc = D.getIdentifierLoc(); - for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) { - const DeclaratorChunk &Chunk = D.getTypeObject(N-I-1); - if (Chunk.Kind == DeclaratorChunk::Function && - Chunk.Fun.hasRefQualifier()) { - Loc = Chunk.Fun.getRefQualifierLoc(); - break; - } - } - - S.Diag(Loc, diag::err_invalid_ref_qualifier_function_type) - << (FnTy->getRefQualifier() == RQ_LValue) - << FixItHint::CreateRemoval(Loc); - } else { - S.Diag(D.getIdentifierLoc(), - diag::err_invalid_ref_qualifier_typedef_function_type_use) - << FreeFunction - << (FnTy->getRefQualifier() == RQ_LValue); - } + // C++11 [dcl.fct]p6 (w/DR1417): + // An attempt to specify a function type with a cv-qualifier-seq or a + // ref-qualifier (including by typedef-name) is ill-formed unless it is: + // - the function type for a non-static member function, + // - the function type to which a pointer to member refers, + // - the top-level function type of a function typedef declaration or + // alias-declaration, + // - the type-id in the default argument of a type-parameter, or + // - the type-id of a template-argument for a type-parameter + if (IsQualifiedFunction && + !(!FreeFunction && + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) && + !IsTypedefName && + D.getContext() != Declarator::TemplateTypeArgContext) { + SourceLocation Loc = D.getSourceRange().getBegin(); + SourceRange RemovalRange; + unsigned I; + if (D.isFunctionDeclarator(I)) { + SmallVector<SourceLocation, 4> RemovalLocs; + const DeclaratorChunk &Chunk = D.getTypeObject(I); + assert(Chunk.Kind == DeclaratorChunk::Function); + if (Chunk.Fun.hasRefQualifier()) + RemovalLocs.push_back(Chunk.Fun.getRefQualifierLoc()); + if (Chunk.Fun.TypeQuals & Qualifiers::Const) + RemovalLocs.push_back(Chunk.Fun.getConstQualifierLoc()); + if (Chunk.Fun.TypeQuals & Qualifiers::Volatile) + RemovalLocs.push_back(Chunk.Fun.getVolatileQualifierLoc()); + // FIXME: We do not track the location of the __restrict qualifier. + //if (Chunk.Fun.TypeQuals & Qualifiers::Restrict) + // RemovalLocs.push_back(Chunk.Fun.getRestrictQualifierLoc()); + if (!RemovalLocs.empty()) { + std::sort(RemovalLocs.begin(), RemovalLocs.end(), + SourceManager::LocBeforeThanCompare(S.getSourceManager())); + RemovalRange = SourceRange(RemovalLocs.front(), RemovalLocs.back()); + Loc = RemovalLocs.front(); } - - // Strip the cv-qualifiers and ref-qualifiers from the type. - FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo(); - EPI.TypeQuals = 0; - EPI.RefQualifier = RQ_None; - - T = Context.getFunctionType(FnTy->getResultType(), - FnTy->arg_type_begin(), - FnTy->getNumArgs(), EPI); } + + S.Diag(Loc, diag::err_invalid_qualified_function_type) + << FreeFunction << D.isFunctionDeclarator() << T + << getFunctionQualifiersAsString(FnTy) + << FixItHint::CreateRemoval(RemovalRange); + + // Strip the cv-qualifiers and ref-qualifiers from the type. + FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo(); + EPI.TypeQuals = 0; + EPI.RefQualifier = RQ_None; + + T = Context.getFunctionType(FnTy->getResultType(), + FnTy->arg_type_begin(), + FnTy->getNumArgs(), EPI); } } |