diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -370,6 +370,12 @@ /// The type for the C ucontext_t type. TypeDecl *ucontext_tDecl = nullptr; + /// The type for the C pthread_t type. + TypeDecl *pthread_tDecl = nullptr; + + /// The type for the C pthread_attr_t type. + TypeDecl *pthread_attr_tDecl = nullptr; + /// Type for the Block descriptor for Blocks CodeGen. /// /// Since this is only used for generation of debug info, it is not @@ -1780,6 +1786,30 @@ return QualType(); } + /// Set the type for the C pthread_t type. + void setpthread_tDecl(TypeDecl *pthread_tDecl) { + this->pthread_tDecl = pthread_tDecl; + } + + /// Retrieve the C pthread_t type. + QualType getpthread_tType() const { + if (pthread_tDecl) + return getTypeDeclType(pthread_tDecl); + return QualType(); + } + + /// Set the type for the C pthread_attr_t type. + void setpthread_attr_tDecl(TypeDecl *pthread_attr_tDecl) { + this->pthread_attr_tDecl = pthread_attr_tDecl; + } + + /// Retrieve the C pthread_attr_t type. + QualType getpthread_attr_tType() const { + if (pthread_attr_tDecl) + return getTypeDeclType(pthread_attr_tDecl); + return QualType(); + } + /// The result type of logical operations, '<', '>', '!=', etc. QualType getLogicalOperationType() const { return getLangOpts().CPlusPlus ? BoolTy : IntTy; @@ -2012,7 +2042,10 @@ GE_Missing_setjmp, /// Missing a type from - GE_Missing_ucontext + GE_Missing_ucontext, + + /// Missing a type from + GE_Missing_pthread }; /// Return the type for the specified builtin. diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -44,6 +44,9 @@ // SJ -> sigjmp_buf // K -> ucontext_t // p -> pid_t +// Q -> pthread_t +// SQ -> pthread_attr_t +// (T) -> function with type T parsed recursively // . -> "...". This may only occur at the end of the function list. // // Types may be prefixed with the following modifiers: @@ -964,7 +967,7 @@ LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_GNU_LANGUAGES) LIBBUILTIN(vfork, "p", "fj", "unistd.h", ALL_LANGUAGES) // POSIX pthread.h -LIBBUILTIN(pthread_create, "", "fC<2,3>", "pthread.h", ALL_GNU_LANGUAGES) +LIBBUILTIN(pthread_create, "iQ*SQC*(v*v*)*v*", "fC<2,3>", "pthread.h", ALL_GNU_LANGUAGES) // POSIX setjmp.h diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1204,7 +1204,13 @@ SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 6, /// C ucontext_t typedef type - SPECIAL_TYPE_UCONTEXT_T = 7 + SPECIAL_TYPE_UCONTEXT_T = 7, + + /// C pthread_t typedef type + SPECIAL_TYPE_PTHREAD_T = 8, + + /// C pthread_attr_t typedef type + SPECIAL_TYPE_PTHREAD_ATTR_T = 9 }; /// The number of special type IDs. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -9231,6 +9231,13 @@ // Builtin Type Computation //===----------------------------------------------------------------------===// +static QualType DecodeFunctionTypeFromStr(const char *&TypeStr, bool IsNested, + bool IsNoReturn, bool IsNoThrow, + bool ForceEmptyTy, + const ASTContext &Context, + ASTContext::GetBuiltinTypeError &Error, + unsigned *IntegerConstantArgs); + /// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the /// pointer over the consumed characters. This returns the resultant type. If /// AllowTypeModifiers is false then modifier like * are not parsed, just basic @@ -9473,6 +9480,25 @@ case 'p': Type = Context.getProcessIDType(); break; + case 'Q': + if (Signed) + Type = Context.getpthread_attr_tType(); + else + Type = Context.getpthread_tType(); + + if (Type.isNull()) { + Error = ASTContext::GE_Missing_pthread; + return {}; + } + break; + case '(': + Type = + DecodeFunctionTypeFromStr(Str, /*IsNested=*/true, /*IsNoReturn=*/false, + /*IsNoThrow=*/false, /*ForceEmptyTy=*/false, + Context, Error, nullptr); + assert(Str[0] == ')' && "unmatched '('"); + Str++; + break; } // If there are modifiers and if we're allowed to parse them, go for it. @@ -9518,30 +9544,38 @@ return Type; } -/// GetBuiltinType - Return the type for the specified builtin. -QualType ASTContext::GetBuiltinType(unsigned Id, - GetBuiltinTypeError &Error, - unsigned *IntegerConstantArgs) const { - const char *TypeStr = BuiltinInfo.getTypeString(Id); +/// DecodeFunctionTypeFromStr - This decodes the entire type descriptor +static QualType DecodeFunctionTypeFromStr(const char *&TypeStr, bool IsNested, + bool IsNoReturn, bool IsNoThrow, + bool ForceEmptyTy, + const ASTContext &Context, + ASTContext::GetBuiltinTypeError &Error, + unsigned *IntegerConstantArgs) { if (TypeStr[0] == '\0') { - Error = GE_Missing_type; + Error = ASTContext::GE_Missing_type; + return {}; + } + + if (TypeStr[0] == ')') { + assert(IsNested && "unmatched ')' found at end of type list"); + Error = ASTContext::GE_Missing_type; return {}; } SmallVector ArgTypes; bool RequiresICE = false; - Error = GE_None; - QualType ResType = DecodeTypeFromStr(TypeStr, *this, Error, + Error = ASTContext::GE_None; + QualType ResType = DecodeTypeFromStr(TypeStr, Context, Error, RequiresICE, true); - if (Error != GE_None) + if (Error != ASTContext::GE_None) return {}; - assert(!RequiresICE && "Result of intrinsic cannot be required to be an ICE"); + assert(!RequiresICE && "Result of function cannot be required to be an ICE"); - while (TypeStr[0] && TypeStr[0] != '.') { - QualType Ty = DecodeTypeFromStr(TypeStr, *this, Error, RequiresICE, true); - if (Error != GE_None) + while (TypeStr[0] && TypeStr[0] != '.' && TypeStr[0] != ')') { + QualType Ty = DecodeTypeFromStr(TypeStr, Context, Error, RequiresICE, true); + if (Error != ASTContext::GE_None) return {}; // If this argument is required to be an IntegerConstantExpression and the @@ -9551,34 +9585,50 @@ // Do array -> pointer decay. The builtin should use the decayed type. if (Ty->isArrayType()) - Ty = getArrayDecayedType(Ty); + Ty = Context.getArrayDecayedType(Ty); ArgTypes.push_back(Ty); } - if (Id == Builtin::BI__GetExceptionInfo) + assert((TypeStr[0] != ')' || IsNested) && + "unmatched ')' found at end of type list"); + + if (ForceEmptyTy) return {}; assert((TypeStr[0] != '.' || TypeStr[1] == 0) && "'.' should only occur at end of builtin type list!"); FunctionType::ExtInfo EI(CC_C); - if (BuiltinInfo.isNoReturn(Id)) EI = EI.withNoReturn(true); + if (IsNoReturn) EI = EI.withNoReturn(true); bool Variadic = (TypeStr[0] == '.'); // We really shouldn't be making a no-proto type here. - if (ArgTypes.empty() && Variadic && !getLangOpts().CPlusPlus) - return getFunctionNoProtoType(ResType, EI); + if (ArgTypes.empty() && Variadic && !Context.getLangOpts().CPlusPlus) + return Context.getFunctionNoProtoType(ResType, EI); FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = EI; EPI.Variadic = Variadic; - if (getLangOpts().CPlusPlus && BuiltinInfo.isNoThrow(Id)) + if (Context.getLangOpts().CPlusPlus && IsNoThrow) EPI.ExceptionSpec.Type = - getLangOpts().CPlusPlus11 ? EST_BasicNoexcept : EST_DynamicNone; + Context.getLangOpts().CPlusPlus11 ? EST_BasicNoexcept : EST_DynamicNone; + + return Context.getFunctionType(ResType, ArgTypes, EPI); +} - return getFunctionType(ResType, ArgTypes, EPI); +/// GetBuiltinType - Return the type for the specified builtin. +QualType ASTContext::GetBuiltinType(unsigned Id, + GetBuiltinTypeError &Error, + unsigned *IntegerConstantArgs) const { + const char *TypeStr = BuiltinInfo.getTypeString(Id); + return DecodeFunctionTypeFromStr(TypeStr, /*IsNested=*/false, + BuiltinInfo.isNoReturn(Id), + BuiltinInfo.isNoThrow(Id), + /*ForceEmptyTy=*/ + Id == Builtin::BI__GetExceptionInfo, + *this, Error, IntegerConstantArgs); } static GVALinkage basicGVALinkageForFunction(const ASTContext &Context, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1943,6 +1943,8 @@ return "setjmp.h"; case ASTContext::GE_Missing_ucontext: return "ucontext.h"; + case ASTContext::GE_Missing_pthread: + return "pthread.h"; } llvm_unreachable("unhandled error kind"); } @@ -5809,6 +5811,10 @@ Context.setsigjmp_bufDecl(NewTD); else if (II->isStr("ucontext_t")) Context.setucontext_tDecl(NewTD); + else if (II->isStr("pthread_t")) + Context.setpthread_tDecl(NewTD); + else if (II->isStr("pthread_attr_t")) + Context.setpthread_attr_tDecl(NewTD); } return NewTD; diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -4560,6 +4560,42 @@ } } } + + if (unsigned Pthread_t = SpecialTypes[SPECIAL_TYPE_PTHREAD_T]) { + QualType Pthread_tType = GetType(Pthread_t); + if (Pthread_tType.isNull()) { + Error("pthread_t type is NULL"); + return; + } + + if (!Context.pthread_tDecl) { + if (const TypedefType *Typedef = Pthread_tType->getAs()) + Context.setpthread_tDecl(Typedef->getDecl()); + else { + const TagType *Tag = Pthread_tType->getAs(); + assert(Tag && "Invalid pthread_t type in AST file"); + Context.setpthread_tDecl(Tag->getDecl()); + } + } + } + + if (unsigned Pthread_attr_t = SpecialTypes[SPECIAL_TYPE_PTHREAD_ATTR_T]) { + QualType Pthread_attr_tType = GetType(Pthread_attr_t); + if (Pthread_attr_tType.isNull()) { + Error("pthread_attr_t type is NULL"); + return; + } + + if (!Context.pthread_attr_tDecl) { + if (const TypedefType *Typedef = Pthread_attr_tType->getAs()) + Context.setpthread_attr_tDecl(Typedef->getDecl()); + else { + const TagType *Tag = Pthread_attr_tType->getAs(); + assert(Tag && "Invalid pthread_attr_t type in AST file"); + Context.setpthread_attr_tDecl(Tag->getDecl()); + } + } + } } ReadPragmaDiagnosticMappings(Context.getDiagnostics()); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -4904,6 +4904,8 @@ AddTypeRef(Context.ObjCClassRedefinitionType, SpecialTypes); AddTypeRef(Context.ObjCSelRedefinitionType, SpecialTypes); AddTypeRef(Context.getucontext_tType(), SpecialTypes); + AddTypeRef(Context.getpthread_tType(), SpecialTypes); + AddTypeRef(Context.getpthread_attr_tType(), SpecialTypes); if (Chain) { // Write the mapping information describing our module dependencies and how diff --git a/clang/test/Analysis/retain-release.m b/clang/test/Analysis/retain-release.m --- a/clang/test/Analysis/retain-release.m +++ b/clang/test/Analysis/retain-release.m @@ -1231,7 +1231,7 @@ typedef unsigned long __darwin_pthread_key_t; typedef __darwin_pthread_key_t pthread_key_t; -int pthread_create(pthread_t *, const pthread_attr_t *, // C-warning{{declaration of built-in function 'pthread_create' requires inclusion of the header }} +int pthread_create(pthread_t *, const pthread_attr_t *, // no-warning void *(*)(void *), void *); int pthread_setspecific(pthread_key_t key, const void *value); diff --git a/clang/test/Sema/implicit-builtin-decl.c b/clang/test/Sema/implicit-builtin-decl.c --- a/clang/test/Sema/implicit-builtin-decl.c +++ b/clang/test/Sema/implicit-builtin-decl.c @@ -66,3 +66,5 @@ // CHECK: FunctionDecl {{.*}} col:6 sigsetjmp ' // CHECK-NOT: FunctionDecl // CHECK: ReturnsTwiceAttr {{.*}} <{{.*}}> Implicit + +int pthread_create(); // expected-warning{{declaration of built-in function 'pthread_create' requires inclusion of the header }}