Decl *Sema::ActOnImplicitEntityDecl(ASTContext &C, SMLoc IDLoc, const IdentifierInfo *IDInfo) { // FIXME: This needs to look at the IMPLICIT statements, if any. DeclSpec DS; DS.SetTypeSpecType(DeclSpec::TST_real); return ActOnEntityDecl(C, DS, IDLoc, IDInfo); }
bool Sema::ActOnObjectArraySpec(ASTContext &C, SourceLocation Loc, DeclSpec &DS, ArrayRef<ArraySpec*> Dimensions) { if(!DS.hasAttributeSpec(DeclSpec::AS_dimension)) DS.setAttributeSpec(DeclSpec::AS_dimension); DS.setDimensions(Dimensions); return false; }
bool Parser::ParseObjectCharLength(SourceLocation Loc, DeclSpec &DS) { if(DS.getTypeSpecType() == TST_character && ConsumeIfPresent(tok::star)) { if (DS.hasLengthSelector()) Diag.Report(getExpectedLoc(), diag::err_duplicate_len_selector); return ParseCharacterStarLengthSpec(DS); } return false; }
bool Sema::ActOnAccessSpec(SourceLocation Loc, DeclSpec &DS, DeclSpec::AC Val) { if (DS.hasAccessSpec(Val)) { Diags.Report(Loc, diag::err_duplicate_access_spec) << DeclSpec::getSpecifierName(Val); return true; } DS.setAccessSpec(Val); return false; }
bool Sema::ActOnAttrSpec(SourceLocation Loc, DeclSpec &DS, DeclSpec::AS Val) { if (DS.hasAttributeSpec(Val)) { Diags.Report(Loc, diag::err_duplicate_attr_spec) << DeclSpec::getSpecifierName(Val); return true; } DS.setAttributeSpec(Val); return false; }
bool Sema::ActOnIntentSpec(SourceLocation Loc, DeclSpec &DS, DeclSpec::IS Val) { if (DS.hasIntentSpec(Val)) { Diags.Report(Loc, diag::err_duplicate_intent_spec) << DeclSpec::getSpecifierName(Val); return true; } DS.setIntentSpec(Val); return false; }
bool Sema::ActOnDimensionAttrSpec(ASTContext &C, SourceLocation Loc, DeclSpec &DS, ArrayRef<ArraySpec*> Dimensions) { if (DS.hasAttributeSpec(DeclSpec::AS_dimension)) { Diags.Report(Loc, diag::err_duplicate_attr_spec) << DeclSpec::getSpecifierName(DeclSpec::AS_dimension); return true; } DS.setAttributeSpec(DeclSpec::AS_dimension); DS.setDimensions(Dimensions); return false; }
bool Parser::ParseCharacterStarLengthSpec(DeclSpec &DS) { ExprResult Len; if(ConsumeIfPresent(tok::l_paren)) { if(ConsumeIfPresent(tok::star)) { DS.setStartLengthSelector(); } else Len = ParseExpectedFollowupExpression("("); if(!ExpectAndConsume(tok::r_paren)) return true; } else Len = ParseExpectedFollowupExpression("*"); if(Len.isInvalid()) return true; if(Len.isUsable()) DS.setLengthSelector(Len.take()); return false; }
void Sema::ActOnTypeDeclSpec(ASTContext &C, SourceLocation Loc, const IdentifierInfo *IDInfo, DeclSpec &DS) { DS.SetTypeSpecType(DeclSpec::TST_struct); auto D = ResolveIdentifier(IDInfo); if(!D) { Diags.Report(Loc, diag::err_undeclared_var_use) << IDInfo; return; } auto Record = dyn_cast<RecordDecl>(D); if(!Record) { Diags.Report(Loc, diag::err_use_of_not_typename) << IDInfo; return; } DS.setRecord(Record); }
/// ParseNonTypeTemplateParameter - Handle the parsing of non-type /// template parameters (e.g., in "template<int Size> class array;"). /// /// template-parameter: /// ... /// parameter-declaration Decl * Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { // Parse the declaration-specifiers (i.e., the type). // FIXME: The type should probably be restricted in some way... Not all // declarators (parts of declarators?) are accepted for parameters. DeclSpec DS; ParseDeclarationSpecifiers(DS); // Parse this as a typename. Declarator ParamDecl(DS, Declarator::TemplateParamContext); ParseDeclarator(ParamDecl); if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { // This probably shouldn't happen - and it's more of a Sema thing, but // basically we didn't parse the type name because we couldn't associate // it with an AST node. we should just skip to the comma or greater. // TODO: This is currently a placeholder for some kind of Sema Error. Diag(Tok.getLocation(), diag::err_parse_error); SkipUntil(tok::comma, tok::greater, true, true); return 0; } // If there is a default value, parse it. // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before // we introduce the template parameter into the local scope. SourceLocation EqualLoc; ExprResult DefaultArg; if (Tok.is(tok::equal)) { EqualLoc = ConsumeToken(); // C++ [temp.param]p15: // When parsing a default template-argument for a non-type // template-parameter, the first non-nested > is taken as the // end of the template-parameter-list rather than a greater-than // operator. GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); DefaultArg = ParseAssignmentExpression(); if (DefaultArg.isInvalid()) SkipUntil(tok::comma, tok::greater, true, true); } // Create the parameter. return Actions.ActOnNonTypeTemplateParameter(getCurScope(), ParamDecl, Depth, Position, EqualLoc, DefaultArg.take()); }
bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS, const DeclSpec &DS, SourceLocation ColonColonLoc) { if (SS.isInvalid() || DS.getTypeSpecType() == DeclSpec::TST_error) return true; assert(DS.getTypeSpecType() == DeclSpec::TST_decltype); QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); if (T.isNull()) return true; if (!T->isDependentType() && !T->getAs<TagType>()) { Diag(DS.getTypeSpecTypeLoc(), diag::err_expected_class_or_namespace) << T << getLangOpts().CPlusPlus; return true; } TypeLocBuilder TLB; DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T); DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc()); SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T), ColonColonLoc); return false; }
/// \brief Convert the specified DeclSpec to the appropriate type object. QualType Sema::ActOnTypeName(ASTContext &C, DeclSpec &DS) { QualType Result; switch (DS.getTypeSpecType()) { case DeclSpec::TST_integer: Result = C.IntegerTy; break; case DeclSpec::TST_unspecified: // FIXME: Correct? case DeclSpec::TST_real: Result = C.RealTy; break; case DeclSpec::TST_doubleprecision: Result = C.DoublePrecisionTy; break; case DeclSpec::TST_character: Result = C.CharacterTy; break; case DeclSpec::TST_logical: Result = C.LogicalTy; break; case DeclSpec::TST_complex: Result = C.ComplexTy; break; case DeclSpec::TST_struct: // FIXME: Finish this. break; } if (!DS.hasAttributes()) return Result; const Type *TypeNode = Result.getTypePtr(); Qualifiers Quals = Qualifiers::fromOpaqueValue(DS.getAttributeSpecs()); Quals.setIntentAttr(DS.getIntentSpec()); Quals.setAccessAttr(DS.getAccessSpec()); QualType EQs = C.getExtQualType(TypeNode, Quals, DS.getKindSelector(), DS.getLengthSelector()); if (!Quals.hasAttributeSpec(Qualifiers::AS_dimension)) return EQs; return ActOnArraySpec(C, EQs, DS.getDimensions()); }
/// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or /// a declaration. We can't tell which we have until we read up to the /// compound-statement in function-definition. TemplateParams, if /// non-NULL, provides the template parameters when we're parsing a /// C++ template-declaration. /// /// function-definition: [C99 6.9.1] /// decl-specs declarator declaration-list[opt] compound-statement /// [C90] function-definition: [C99 6.7.1] - implicit int result /// [C90] decl-specs[opt] declarator declaration-list[opt] compound-statement /// /// declaration: [C99 6.7] /// declaration-specifiers init-declarator-list[opt] ';' /// [!C99] init-declarator-list ';' [TODO: warn in c99 mode] /// [OMP] threadprivate-directive [TODO] /// Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { // Parse the common declaration-specifiers piece. DeclSpec DS; ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { ConsumeToken(); DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS); return Actions.ConvertDeclToDeclGroup(TheDecl); } // ObjC2 allows prefix attributes on class interfaces and protocols. // FIXME: This still needs better diagnostics. We should only accept // attributes here, no types, etc. if (getLang().ObjC2 && Tok.is(tok::at)) { SourceLocation AtLoc = ConsumeToken(); // the "@" if (!Tok.isObjCAtKeyword(tok::objc_interface) && !Tok.isObjCAtKeyword(tok::objc_protocol)) { Diag(Tok, diag::err_objc_unexpected_attr); SkipUntil(tok::semi); // FIXME: better skip? return DeclGroupPtrTy(); } const char *PrevSpec = 0; unsigned DiagID; if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec, DiagID)) Diag(AtLoc, DiagID) << PrevSpec; DeclPtrTy TheDecl; if (Tok.isObjCAtKeyword(tok::objc_protocol)) TheDecl = ParseObjCAtProtocolDeclaration(AtLoc, DS.getAttributes()); else TheDecl = ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes()); return Actions.ConvertDeclToDeclGroup(TheDecl); } // If the declspec consisted only of 'extern' and we have a string // literal following it, this must be a C++ linkage specifier like // 'extern "C"'. if (Tok.is(tok::string_literal) && getLang().CPlusPlus && DS.getStorageClassSpec() == DeclSpec::SCS_extern && DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) { DeclPtrTy TheDecl = ParseLinkage(Declarator::FileContext); return Actions.ConvertDeclToDeclGroup(TheDecl); } // Parse the first declarator. Declarator DeclaratorInfo(DS, Declarator::FileContext); ParseDeclarator(DeclaratorInfo); // Error parsing the declarator? if (!DeclaratorInfo.hasName()) { // If so, skip until the semi-colon or a }. SkipUntil(tok::r_brace, true, true); if (Tok.is(tok::semi)) ConsumeToken(); return DeclGroupPtrTy(); } // If we have a declaration or declarator list, handle it. if (isDeclarationAfterDeclarator()) { // Parse the init-declarator-list for a normal declaration. DeclGroupPtrTy DG = ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo); // Eat the semi colon after the declaration. ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); return DG; } if (DeclaratorInfo.isFunctionDeclarator() && isStartOfFunctionDefinition()) { if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { Diag(Tok, diag::err_function_declared_typedef); if (Tok.is(tok::l_brace)) { // This recovery skips the entire function body. It would be nice // to simply call ParseFunctionDefinition() below, however Sema // assumes the declarator represents a function, not a typedef. ConsumeBrace(); SkipUntil(tok::r_brace, true); } else { SkipUntil(tok::semi); } return DeclGroupPtrTy(); } DeclPtrTy TheDecl = ParseFunctionDefinition(DeclaratorInfo); return Actions.ConvertDeclToDeclGroup(TheDecl); } if (DeclaratorInfo.isFunctionDeclarator()) Diag(Tok, diag::err_expected_fn_body); else Diag(Tok, diag::err_invalid_token_after_toplevel_declarator); SkipUntil(tok::semi); return DeclGroupPtrTy(); }
/// ParseDeclarationTypeSpec - Parse a declaration type spec construct. /// /// [R502]: /// declaration-type-spec := /// intrinsic-type-spec /// or TYPE ( derived-type-spec ) /// or CLASS ( derived-type-spec ) /// or CLASS ( * ) bool Parser::ParseDeclarationTypeSpec(DeclSpec &DS, bool AllowSelectors, bool AllowOptionalCommaAfterCharLength) { // [R403]: // intrinsic-type-spec := // INTEGER [ kind-selector ] // or REAL [ kind-selector ] // or DOUBLE PRECISION // or COMPLEX [ kind-selector ] // or DOUBLE COMPLEX // or CHARACTER [ char-selector ] // or BYTE // or LOGICAL [ kind-selector ] switch (Tok.getKind()) { default: DS.SetTypeSpecType(DeclSpec::TST_unspecified); break; case tok::kw_INTEGER: DS.SetTypeSpecType(DeclSpec::TST_integer); break; case tok::kw_REAL: DS.SetTypeSpecType(DeclSpec::TST_real); break; case tok::kw_COMPLEX: DS.SetTypeSpecType(DeclSpec::TST_complex); break; case tok::kw_CHARACTER: DS.SetTypeSpecType(DeclSpec::TST_character); break; case tok::kw_BYTE: DS.SetTypeSpecType(DeclSpec::TST_logical); DS.setByte(); // equivalent to Kind = 1 break; case tok::kw_LOGICAL: DS.SetTypeSpecType(DeclSpec::TST_logical); break; case tok::kw_DOUBLEPRECISION: DS.SetTypeSpecType(DeclSpec::TST_real); DS.setDoublePrecision(); // equivalent to Kind = 8 break; case tok::kw_DOUBLECOMPLEX: DS.SetTypeSpecType(DeclSpec::TST_complex); DS.setDoublePrecision(); // equivalent to Kind = 8 break; } if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) if (ParseTypeOrClassDeclTypeSpec(DS)) return true; ExprResult Kind; ExprResult Len; // FIXME: no Kind for double complex, double precision and byte switch (DS.getTypeSpecType()) { case DeclSpec::TST_struct: break; default: ConsumeToken(); if (ConsumeIfPresent(tok::star)) { // FIXME: proper obsolete COMPLEX*16 support ConsumeAnyToken(); DS.setDoublePrecision(); } if (!AllowSelectors) break; if (ConsumeIfPresent(tok::l_paren)) { Kind = ParseSelector(true); if (Kind.isInvalid()) return true; if(!ExpectAndConsume(tok::r_paren, 0, "", tok::r_paren)) return true; } break; case DeclSpec::TST_character: // [R424]: // char-selector := // length-selector // or ( LEN = type-param-value , KIND = scalar-int-initialization-expr ) // or ( type-param-value , # // # [ KIND = ] scalar-int-initialization-expr ) // or ( KIND = scalar-int-initialization-expr [, LEN = type-param-value]) // // [R425]: // length-selector := // ( [ LEN = ] type-param-value ) // or * char-length [,] // // [R426]: // char-length := // ( type-param-value ) // or scalar-int-literal-constant // // [R402]: // type-param-value := // scalar-int-expr // or * // or : ConsumeToken(); if(ConsumeIfPresent(tok::star)) { ParseCharacterStarLengthSpec(DS); if(AllowOptionalCommaAfterCharLength) ConsumeIfPresent(tok::comma); } else { if (!AllowSelectors) break; if(ConsumeIfPresent(tok::l_paren)) { if(IsPresent(tok::kw_LEN)) { Len = ParseSelector(false); if (Len.isInvalid()) return true; } else if(IsPresent(tok::kw_KIND)) { Kind = ParseSelector(true); if (Kind.isInvalid()) return true; } else { Len = ParseExpectedFollowupExpression("("); if(Len.isInvalid()) return true; } if(ConsumeIfPresent(tok::comma)) { // FIXME: if (Tok.is(tok::kw_LEN)) { if (Len.isInvalid()) return Diag.ReportError(Tok.getLocation(), "multiple LEN selectors for this type"); Len = ParseSelector(false); if (Len.isInvalid()) return true; } else if (Tok.is(tok::kw_KIND)) { if (Kind.isInvalid()) return Diag.ReportError(Tok.getLocation(), "multiple KIND selectors for this type"); Kind = ParseSelector(true); if (Kind.isInvalid()) return true; } else { if (Kind.isInvalid()) return Diag.ReportError(Tok.getLocation(), "multiple KIND selectors for this type"); ExprResult KindExpr = ParseExpression(); Kind = KindExpr; } } if(!ExpectAndConsume(tok::r_paren)) return true; } } break; } // Set the selectors for declspec. if(Kind.isUsable()) DS.setKindSelector(Kind.get()); if(Len.isUsable()) DS.setLengthSelector(Len.get()); return false; }
/// \brief Convert the specified declspec to the appropriate type /// object. /// \param DS the declaration specifiers /// \returns The type described by the declaration specifiers, or NULL /// if there was an error. QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS) { // FIXME: Should move the logic from DeclSpec::Finish to here for validity // checking. QualType Result; switch (DS.getTypeSpecType()) { case DeclSpec::TST_void: Result = Context.VoidTy; break; case DeclSpec::TST_char: if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified) Result = Context.CharTy; else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) Result = Context.SignedCharTy; else { assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned && "Unknown TSS value"); Result = Context.UnsignedCharTy; } break; case DeclSpec::TST_wchar: if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified) Result = Context.WCharTy; else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) { Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) << DS.getSpecifierName(DS.getTypeSpecType()); Result = Context.getSignedWCharType(); } else { assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned && "Unknown TSS value"); Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) << DS.getSpecifierName(DS.getTypeSpecType()); Result = Context.getUnsignedWCharType(); } break; case DeclSpec::TST_unspecified: // "<proto1,proto2>" is an objc qualified ID with a missing id. if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { Result = Context.getObjCQualifiedIdType((ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); break; } // Unspecified typespec defaults to int in C90. However, the C90 grammar // [C90 6.5] only allows a decl-spec if there was *some* type-specifier, // type-qualifier, or storage-class-specifier. If not, emit an extwarn. // Note that the one exception to this is function definitions, which are // allowed to be completely missing a declspec. This is handled in the // parser already though by it pretending to have seen an 'int' in this // case. if (getLangOptions().ImplicitInt) { // In C89 mode, we only warn if there is a completely missing declspec // when one is not allowed. if (DS.isEmpty()) Diag(DS.getSourceRange().getBegin(), diag::warn_missing_declspec) << CodeModificationHint::CreateInsertion(DS.getSourceRange().getBegin(), "int"); } else if (!DS.hasTypeSpecifier()) { // C99 and C++ require a type specifier. For example, C99 6.7.2p2 says: // "At least one type specifier shall be given in the declaration // specifiers in each declaration, and in the specifier-qualifier list in // each struct declaration and type name." // FIXME: Does Microsoft really have the implicit int extension in C++? unsigned DK = getLangOptions().CPlusPlus && !getLangOptions().Microsoft? diag::err_missing_type_specifier : diag::warn_missing_type_specifier; Diag(DS.getSourceRange().getBegin(), DK); // FIXME: If we could guarantee that the result would be // well-formed, it would be useful to have a code insertion hint // here. However, after emitting this warning/error, we often // emit other errors. } // FALL THROUGH. case DeclSpec::TST_int: { if (DS.getTypeSpecSign() != DeclSpec::TSS_unsigned) { switch (DS.getTypeSpecWidth()) { case DeclSpec::TSW_unspecified: Result = Context.IntTy; break; case DeclSpec::TSW_short: Result = Context.ShortTy; break; case DeclSpec::TSW_long: Result = Context.LongTy; break; case DeclSpec::TSW_longlong: Result = Context.LongLongTy; break; } } else { switch (DS.getTypeSpecWidth()) { case DeclSpec::TSW_unspecified: Result = Context.UnsignedIntTy; break; case DeclSpec::TSW_short: Result = Context.UnsignedShortTy; break; case DeclSpec::TSW_long: Result = Context.UnsignedLongTy; break; case DeclSpec::TSW_longlong: Result =Context.UnsignedLongLongTy; break; } } break; } case DeclSpec::TST_float: Result = Context.FloatTy; break; case DeclSpec::TST_double: if (DS.getTypeSpecWidth() == DeclSpec::TSW_long) Result = Context.LongDoubleTy; else Result = Context.DoubleTy; break; case DeclSpec::TST_bool: Result = Context.BoolTy; break; // _Bool or bool case DeclSpec::TST_decimal32: // _Decimal32 case DeclSpec::TST_decimal64: // _Decimal64 case DeclSpec::TST_decimal128: // _Decimal128 assert(0 && "FIXME: GNU decimal extensions not supported yet!"); case DeclSpec::TST_class: case DeclSpec::TST_enum: case DeclSpec::TST_union: case DeclSpec::TST_struct: { Decl *D = static_cast<Decl *>(DS.getTypeRep()); assert(D && "Didn't get a decl for a class/enum/union/struct?"); assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && DS.getTypeSpecSign() == 0 && "Can't handle qualifiers on typedef names yet!"); // TypeQuals handled by caller. Result = Context.getTypeDeclType(cast<TypeDecl>(D)); break; } case DeclSpec::TST_typename: { assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && DS.getTypeSpecSign() == 0 && "Can't handle qualifiers on typedef names yet!"); Result = QualType::getFromOpaquePtr(DS.getTypeRep()); if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { // FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so // we have this "hack" for now... if (const ObjCInterfaceType *Interface = Result->getAsObjCInterfaceType()) Result = Context.getObjCQualifiedInterfaceType(Interface->getDecl(), (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); else if (Result == Context.getObjCIdType()) // id<protocol-list> Result = Context.getObjCQualifiedIdType((ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); else if (Result == Context.getObjCClassType()) // Class<protocol-list> Diag(DS.getSourceRange().getBegin(), diag::err_qualified_class_unsupported) << DS.getSourceRange(); else Diag(DS.getSourceRange().getBegin(), diag::err_invalid_protocol_qualifiers) << DS.getSourceRange(); } // TypeQuals handled by caller. break; } case DeclSpec::TST_typeofType: Result = QualType::getFromOpaquePtr(DS.getTypeRep()); assert(!Result.isNull() && "Didn't get a type for typeof?"); // TypeQuals handled by caller. Result = Context.getTypeOfType(Result); break; case DeclSpec::TST_typeofExpr: { Expr *E = static_cast<Expr *>(DS.getTypeRep()); assert(E && "Didn't get an expression for typeof?"); // TypeQuals handled by caller. Result = Context.getTypeOfExprType(E); break; } case DeclSpec::TST_error: return QualType(); } // Handle complex types. if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) { if (getLangOptions().Freestanding) Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex); Result = Context.getComplexType(Result); } assert(DS.getTypeSpecComplex() != DeclSpec::TSC_imaginary && "FIXME: imaginary types not supported yet!"); // See if there are any attributes on the declspec that apply to the type (as // opposed to the decl). if (const AttributeList *AL = DS.getAttributes()) ProcessTypeAttributeList(Result, AL); // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { // Enforce C99 6.7.3p2: "Types other than pointer types derived from object // or incomplete types shall not be restrict-qualified." C++ also allows // restrict-qualified references. if (TypeQuals & QualType::Restrict) { if (Result->isPointerType() || Result->isReferenceType()) { QualType EltTy = Result->isPointerType() ? Result->getAsPointerType()->getPointeeType() : Result->getAsReferenceType()->getPointeeType(); // If we have a pointer or reference, the pointee must have an object // incomplete type. if (!EltTy->isIncompleteOrObjectType()) { Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_invalid_pointee) << EltTy << DS.getSourceRange(); TypeQuals &= ~QualType::Restrict; // Remove the restrict qualifier. } } else { Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_not_pointer) << Result << DS.getSourceRange(); TypeQuals &= ~QualType::Restrict; // Remove the restrict qualifier. } } // Warn about CV qualifiers on functions: C99 6.7.3p8: "If the specification // of a function type includes any type qualifiers, the behavior is // undefined." if (Result->isFunctionType() && TypeQuals) { // Get some location to point at, either the C or V location. SourceLocation Loc; if (TypeQuals & QualType::Const) Loc = DS.getConstSpecLoc(); else { assert((TypeQuals & QualType::Volatile) && "Has CV quals but not C or V?"); Loc = DS.getVolatileSpecLoc(); } Diag(Loc, diag::warn_typecheck_function_qualifiers) << Result << 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. // FIXME: Shouldn't we be checking SCS_typedef here? if (DS.getTypeSpecType() == DeclSpec::TST_typename && TypeQuals && Result->isReferenceType()) { TypeQuals &= ~QualType::Const; TypeQuals &= ~QualType::Volatile; } Result = Result.getQualifiedType(TypeQuals); } return Result; }
/// \brief Convert the specified DeclSpec to the appropriate type object. QualType Sema::ActOnTypeName(ASTContext &C, DeclSpec &DS) { QualType Result; switch (DS.getTypeSpecType()) { case DeclSpec::TST_integer: Result = C.IntegerTy; break; case DeclSpec::TST_unspecified: // FIXME: Correct? case DeclSpec::TST_real: Result = C.RealTy; break; case DeclSpec::TST_character: if(DS.isStarLengthSelector()) Result = C.NoLengthCharacterTy; else if(DS.hasLengthSelector()) Result = QualType(C.getCharacterType( EvalAndCheckCharacterLength(DS.getLengthSelector())), 0); else Result = C.CharacterTy; break; case DeclSpec::TST_logical: Result = C.LogicalTy; break; case DeclSpec::TST_complex: Result = C.ComplexTy; break; case DeclSpec::TST_struct: if(!DS.getRecord()) Result = C.RealTy; else Result = C.getRecordType(DS.getRecord()); break; } Type::TypeKind Kind = Type::NoKind; if(DS.hasKindSelector()) Kind = EvalAndCheckTypeKind(Result, DS.getKindSelector()); if(Kind != Type::NoKind || DS.isDoublePrecision() || DS.isByte()) { switch (DS.getTypeSpecType()) { case DeclSpec::TST_integer: Result = Kind == Type::NoKind? C.IntegerTy : QualType(C.getBuiltinType(BuiltinType::Integer, Kind, true), 0); break; case DeclSpec::TST_real: Result = Kind == Type::NoKind? (DS.isDoublePrecision()? C.DoublePrecisionTy : C.RealTy) : QualType(C.getBuiltinType(BuiltinType::Real, Kind, true), 0); break; case DeclSpec::TST_logical: Result = Kind == Type::NoKind? (DS.isByte()? C.ByteTy : C.LogicalTy) : QualType(C.getBuiltinType(BuiltinType::Logical, Kind, true), 0); break; case DeclSpec::TST_complex: Result = Kind == Type::NoKind? (DS.isDoublePrecision()? C.DoubleComplexTy : C.ComplexTy) : QualType(C.getBuiltinType(BuiltinType::Complex, Kind, true), 0); break; default: break; } } if (!DS.hasAttributes()) return Result; const Type *TypeNode = Result.getTypePtr(); Qualifiers Quals = Qualifiers::fromOpaqueValue(DS.getAttributeSpecs()); Quals.setIntentAttr(DS.getIntentSpec()); Quals.setAccessAttr(DS.getAccessSpec()); Result = C.getExtQualType(TypeNode, Quals); if (!Quals.hasAttributeSpec(Qualifiers::AS_dimension)) return Result; return ActOnArraySpec(C, Result, DS.getDimensions()); }
/// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides /// types for a function with a K&R-style identifier list for arguments. void Parser::ParseKNRParamDeclarations(Declarator &D) { // We know that the top-level of this declarator is a function. DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; // Enter function-declaration scope, limiting any declarators to the // function prototype scope, including parameter declarators. ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope); // Read all the argument declarations. while (isDeclarationSpecifier()) { SourceLocation DSStart = Tok.getLocation(); // Parse the common declaration-specifiers piece. DeclSpec DS; ParseDeclarationSpecifiers(DS); // C99 6.9.1p6: 'each declaration in the declaration list shall have at // least one declarator'. // NOTE: GCC just makes this an ext-warn. It's not clear what it does with // the declarations though. It's trivial to ignore them, really hard to do // anything else with them. if (Tok.is(tok::semi)) { Diag(DSStart, diag::err_declaration_does_not_declare_param); ConsumeToken(); continue; } // C99 6.9.1p6: Declarations shall contain no storage-class specifiers other // than register. if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified && DS.getStorageClassSpec() != DeclSpec::SCS_register) { Diag(DS.getStorageClassSpecLoc(), diag::err_invalid_storage_class_in_func_decl); DS.ClearStorageClassSpecs(); } if (DS.isThreadSpecified()) { Diag(DS.getThreadSpecLoc(), diag::err_invalid_storage_class_in_func_decl); DS.ClearStorageClassSpecs(); } // Parse the first declarator attached to this declspec. Declarator ParmDeclarator(DS, Declarator::KNRTypeListContext); ParseDeclarator(ParmDeclarator); // Handle the full declarator list. while (1) { Action::AttrTy *AttrList; // If attributes are present, parse them. if (Tok.is(tok::kw___attribute)) // FIXME: attach attributes too. AttrList = ParseAttributes(); // Ask the actions module to compute the type for this declarator. Action::DeclPtrTy Param = Actions.ActOnParamDeclarator(CurScope, ParmDeclarator); if (Param && // A missing identifier has already been diagnosed. ParmDeclarator.getIdentifier()) { // Scan the argument list looking for the correct param to apply this // type. for (unsigned i = 0; ; ++i) { // C99 6.9.1p6: those declarators shall declare only identifiers from // the identifier list. if (i == FTI.NumArgs) { Diag(ParmDeclarator.getIdentifierLoc(), diag::err_no_matching_param) << ParmDeclarator.getIdentifier(); break; } if (FTI.ArgInfo[i].Ident == ParmDeclarator.getIdentifier()) { // Reject redefinitions of parameters. if (FTI.ArgInfo[i].Param) { Diag(ParmDeclarator.getIdentifierLoc(), diag::err_param_redefinition) << ParmDeclarator.getIdentifier(); } else { FTI.ArgInfo[i].Param = Param; } break; } } } // If we don't have a comma, it is either the end of the list (a ';') or // an error, bail out. if (Tok.isNot(tok::comma)) break; // Consume the comma. ConsumeToken(); // Parse the next declarator. ParmDeclarator.clear(); ParseDeclarator(ParmDeclarator); } if (Tok.is(tok::semi)) { ConsumeToken(); } else { Diag(Tok, diag::err_parse_error); // Skip to end of block or statement SkipUntil(tok::semi, true); if (Tok.is(tok::semi)) ConsumeToken(); } } // The actions module must verify that all arguments were declared. Actions.ActOnFinishKNRParamDeclarations(CurScope, D, Tok.getLocation()); }